1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef LIBPANDABASE_OS_MUTEX_H 17 #define LIBPANDABASE_OS_MUTEX_H 18 19 #if defined(PANDA_USE_FUTEX) 20 #include "platforms/unix/libpandabase/futex/mutex.h" 21 #elif !defined(PANDA_TARGET_UNIX) && !defined(PANDA_TARGET_WINDOWS) 22 #error "Unsupported platform" 23 #endif 24 25 #include "clang.h" 26 #include "macros.h" 27 28 #include <atomic> 29 #include <pthread.h> 30 31 namespace panda::os::memory { 32 33 // Dummy lock which locks nothing 34 // but has the same methods as RWLock and Mutex. 35 // Can be used in Locks Holders. 36 class DummyLock { 37 public: Lock()38 void Lock() const {} Unlock()39 void Unlock() const {} ReadLock()40 void ReadLock() const {} WriteLock()41 void WriteLock() const {} 42 }; 43 44 #if defined(PANDA_USE_FUTEX) 45 using Mutex = panda::os::unix::memory::futex::Mutex; 46 using RecursiveMutex = panda::os::unix::memory::futex::RecursiveMutex; 47 using RWLock = panda::os::unix::memory::futex::RWLock; 48 using ConditionVariable = panda::os::unix::memory::futex::ConditionVariable; 49 #else 50 class ConditionVariable; 51 52 class CAPABILITY("mutex") Mutex { 53 public: 54 explicit Mutex(bool is_init = true); 55 56 ~Mutex(); 57 58 void Lock() ACQUIRE(); 59 60 bool TryLock() TRY_ACQUIRE(true); 61 62 void Unlock() RELEASE(); 63 64 // TODO: Extract common part as an interface. DoNotCheckOnDeadlock()65 static bool DoNotCheckOnDeadlock() 66 { 67 return no_check_for_deadlock_; 68 } 69 IgnoreChecksOnDeadlock()70 static void IgnoreChecksOnDeadlock() 71 { 72 no_check_for_deadlock_ = true; 73 } 74 75 protected: 76 void Init(pthread_mutexattr_t *attrs); 77 78 private: 79 pthread_mutex_t mutex_; 80 81 // This field is set to false in case of deadlock with daemon threads (only daemon threads 82 // are not finished and they have state IS_BLOCKED). In this case we should terminate 83 // those threads ignoring failures on lock structures destructors. 84 static std::atomic_bool no_check_for_deadlock_; 85 86 NO_COPY_SEMANTIC(Mutex); 87 NO_MOVE_SEMANTIC(Mutex); 88 89 friend ConditionVariable; 90 }; 91 92 class CAPABILITY("mutex") RecursiveMutex : public Mutex { 93 public: 94 RecursiveMutex(); 95 96 ~RecursiveMutex() = default; 97 98 NO_COPY_SEMANTIC(RecursiveMutex); 99 NO_MOVE_SEMANTIC(RecursiveMutex); 100 }; 101 102 class CAPABILITY("mutex") RWLock { 103 public: 104 RWLock(); 105 106 ~RWLock(); 107 108 void ReadLock() ACQUIRE_SHARED(); 109 110 void WriteLock() ACQUIRE(); 111 112 bool TryReadLock() TRY_ACQUIRE_SHARED(true); 113 114 bool TryWriteLock() TRY_ACQUIRE(true); 115 116 void Unlock() RELEASE_GENERIC(); 117 118 private: 119 pthread_rwlock_t rwlock_; 120 121 NO_COPY_SEMANTIC(RWLock); 122 NO_MOVE_SEMANTIC(RWLock); 123 }; 124 125 // Some RTOS could not have support for condition variables, so this primitive should be used carefully 126 class ConditionVariable { 127 public: 128 ConditionVariable(); 129 130 ~ConditionVariable(); 131 132 void Signal(); 133 134 void SignalAll(); 135 136 void Wait(Mutex *mutex); 137 138 bool TimedWait(Mutex *mutex, uint64_t ms, uint64_t ns = 0, bool is_absolute = false); 139 140 private: 141 pthread_cond_t cond_; 142 143 NO_COPY_SEMANTIC(ConditionVariable); 144 NO_MOVE_SEMANTIC(ConditionVariable); 145 }; 146 #endif // PANDA_USE_FUTEX 147 148 using PandaThreadKey = pthread_key_t; 149 const auto PandaGetspecific = pthread_getspecific; // NOLINT(readability-identifier-naming) 150 const auto PandaSetspecific = pthread_setspecific; // NOLINT(readability-identifier-naming) 151 const auto PandaThreadKeyCreate = pthread_key_create; // NOLINT(readability-identifier-naming) 152 153 template <class T, bool need_lock = true> 154 class SCOPED_CAPABILITY LockHolder { 155 public: LockHolder(T & lock)156 explicit LockHolder(T &lock) ACQUIRE(lock) : lock_(lock) 157 { 158 if constexpr (need_lock) { // NOLINTNEXTLINE(readability-braces-around-statements) 159 lock_.Lock(); 160 } 161 } 162 RELEASE()163 ~LockHolder() RELEASE() 164 { 165 if constexpr (need_lock) { // NOLINTNEXTLINE(readability-braces-around-statements) 166 lock_.Unlock(); 167 } 168 } 169 170 private: 171 T &lock_; 172 173 NO_COPY_SEMANTIC(LockHolder); 174 NO_MOVE_SEMANTIC(LockHolder); 175 }; 176 177 template <class T, bool need_lock = true> 178 class SCOPED_CAPABILITY ReadLockHolder { 179 public: ReadLockHolder(T & lock)180 explicit ReadLockHolder(T &lock) ACQUIRE_SHARED(lock) : lock_(lock) 181 { 182 if constexpr (need_lock) { // NOLINTNEXTLINE(readability-braces-around-statements) 183 lock_.ReadLock(); 184 } 185 } 186 RELEASE()187 ~ReadLockHolder() RELEASE() 188 { 189 if constexpr (need_lock) { // NOLINTNEXTLINE(readability-braces-around-statements) 190 lock_.Unlock(); 191 } 192 } 193 194 private: 195 T &lock_; 196 197 NO_COPY_SEMANTIC(ReadLockHolder); 198 NO_MOVE_SEMANTIC(ReadLockHolder); 199 }; 200 201 template <class T, bool need_lock = true> 202 class SCOPED_CAPABILITY WriteLockHolder { 203 public: WriteLockHolder(T & lock)204 explicit WriteLockHolder(T &lock) ACQUIRE(lock) : lock_(lock) 205 { 206 if constexpr (need_lock) { // NOLINTNEXTLINE(readability-braces-around-statements) 207 lock_.WriteLock(); 208 } 209 } 210 RELEASE()211 ~WriteLockHolder() RELEASE() 212 { 213 if constexpr (need_lock) { // NOLINTNEXTLINE(readability-braces-around-statements) 214 lock_.Unlock(); 215 } 216 } 217 218 private: 219 T &lock_; 220 221 NO_COPY_SEMANTIC(WriteLockHolder); 222 NO_MOVE_SEMANTIC(WriteLockHolder); 223 }; 224 225 } // namespace panda::os::memory 226 227 #endif // LIBPANDABASE_OS_MUTEX_H 228