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/macros/config.h" 16 #include "src/__support/threads/linux/futex_utils.h" 17 #include "src/__support/threads/linux/raw_mutex.h" 18 #include "src/__support/threads/mutex_common.h" 19 20 namespace LIBC_NAMESPACE_DECL { 21 22 // TODO: support shared/recursive/robust mutexes. 23 class Mutex final : private RawMutex { 24 // reserved timed, may be useful when combined with other flags. 25 unsigned char timed; 26 unsigned char recursive; 27 unsigned char robust; 28 unsigned char pshared; 29 30 // TLS address may not work across forked processes. Use thread id instead. 31 pid_t owner; 32 unsigned long long lock_count; 33 34 public: Mutex(bool is_timed,bool is_recursive,bool is_robust,bool is_pshared)35 LIBC_INLINE constexpr Mutex(bool is_timed, bool is_recursive, bool is_robust, 36 bool is_pshared) 37 : RawMutex(), timed(is_timed), recursive(is_recursive), robust(is_robust), 38 pshared(is_pshared), owner(0), lock_count(0) {} 39 init(Mutex * mutex,bool is_timed,bool isrecur,bool isrobust,bool is_pshared)40 LIBC_INLINE static MutexError init(Mutex *mutex, bool is_timed, bool isrecur, 41 bool isrobust, bool is_pshared) { 42 RawMutex::init(mutex); 43 mutex->timed = is_timed; 44 mutex->recursive = isrecur; 45 mutex->robust = isrobust; 46 mutex->pshared = is_pshared; 47 mutex->owner = 0; 48 mutex->lock_count = 0; 49 return MutexError::NONE; 50 } 51 destroy(Mutex * lock)52 LIBC_INLINE static MutexError destroy(Mutex *lock) { 53 LIBC_ASSERT(lock->owner == 0 && lock->lock_count == 0 && 54 "Mutex destroyed while being locked."); 55 RawMutex::destroy(lock); 56 return MutexError::NONE; 57 } 58 59 // TODO: record owner and lock count. lock()60 LIBC_INLINE MutexError lock() { 61 // Since timeout is not specified, we do not need to check the return value. 62 this->RawMutex::lock( 63 /* timeout=*/cpp::nullopt, this->pshared); 64 return MutexError::NONE; 65 } 66 67 // TODO: record owner and lock count. timed_lock(internal::AbsTimeout abs_time)68 LIBC_INLINE MutexError timed_lock(internal::AbsTimeout abs_time) { 69 if (this->RawMutex::lock(abs_time, this->pshared)) 70 return MutexError::NONE; 71 return MutexError::TIMEOUT; 72 } 73 unlock()74 LIBC_INLINE MutexError unlock() { 75 if (this->RawMutex::unlock(this->pshared)) 76 return MutexError::NONE; 77 return MutexError::UNLOCK_WITHOUT_LOCK; 78 } 79 80 // TODO: record owner and lock count. try_lock()81 LIBC_INLINE MutexError try_lock() { 82 if (this->RawMutex::try_lock()) 83 return MutexError::NONE; 84 return MutexError::BUSY; 85 } 86 }; 87 88 } // namespace LIBC_NAMESPACE_DECL 89 90 #endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_MUTEX_H 91