1 //===--- Implementation of a Linux mutex class ------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_MUTEX_H 10 #define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_MUTEX_H 11 12 #include "hdr/types/pid_t.h" 13 #include "src/__support/CPP/optional.h" 14 #include "src/__support/libc_assert.h" 15 #include "src/__support/threads/linux/futex_utils.h" 16 #include "src/__support/threads/linux/raw_mutex.h" 17 #include "src/__support/threads/mutex_common.h" 18 19 namespace LIBC_NAMESPACE { 20 21 // TODO: support shared/recursive/robust mutexes. 22 class Mutex final : private RawMutex { 23 // reserved timed, may be useful when combined with other flags. 24 unsigned char timed; 25 unsigned char recursive; 26 unsigned char robust; 27 unsigned char pshared; 28 29 // TLS address may not work across forked processes. Use thread id instead. 30 pid_t owner; 31 unsigned long long lock_count; 32 33 public: Mutex(bool is_timed,bool is_recursive,bool is_robust,bool is_pshared)34 LIBC_INLINE constexpr Mutex(bool is_timed, bool is_recursive, bool is_robust, 35 bool is_pshared) 36 : RawMutex(), timed(is_timed), recursive(is_recursive), robust(is_robust), 37 pshared(is_pshared), owner(0), lock_count(0) {} 38 init(Mutex * mutex,bool is_timed,bool isrecur,bool isrobust,bool is_pshared)39 LIBC_INLINE static MutexError init(Mutex *mutex, bool is_timed, bool isrecur, 40 bool isrobust, bool is_pshared) { 41 RawMutex::init(mutex); 42 mutex->timed = is_timed; 43 mutex->recursive = isrecur; 44 mutex->robust = isrobust; 45 mutex->pshared = is_pshared; 46 mutex->owner = 0; 47 mutex->lock_count = 0; 48 return MutexError::NONE; 49 } 50 destroy(Mutex * lock)51 LIBC_INLINE static MutexError destroy(Mutex *lock) { 52 LIBC_ASSERT(lock->owner == 0 && lock->lock_count == 0 && 53 "Mutex destroyed while being locked."); 54 RawMutex::destroy(lock); 55 return MutexError::NONE; 56 } 57 58 // TODO: record owner and lock count. lock()59 LIBC_INLINE MutexError lock() { 60 // Since timeout is not specified, we do not need to check the return value. 61 this->RawMutex::lock( 62 /* timeout=*/cpp::nullopt, this->pshared); 63 return MutexError::NONE; 64 } 65 66 // TODO: record owner and lock count. timed_lock(internal::AbsTimeout abs_time)67 LIBC_INLINE MutexError timed_lock(internal::AbsTimeout abs_time) { 68 if (this->RawMutex::lock(abs_time, this->pshared)) 69 return MutexError::NONE; 70 return MutexError::TIMEOUT; 71 } 72 unlock()73 LIBC_INLINE MutexError unlock() { 74 if (this->RawMutex::unlock(this->pshared)) 75 return MutexError::NONE; 76 return MutexError::UNLOCK_WITHOUT_LOCK; 77 } 78 79 // TODO: record owner and lock count. try_lock()80 LIBC_INLINE MutexError try_lock() { 81 if (this->RawMutex::try_lock()) 82 return MutexError::NONE; 83 return MutexError::BUSY; 84 } 85 }; 86 87 } // namespace LIBC_NAMESPACE 88 89 #endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_MUTEX_H 90