1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_BASE_PLATFORM_MUTEX_H_ 6 #define V8_BASE_PLATFORM_MUTEX_H_ 7 8 #include "src/base/lazy-instance.h" 9 #if V8_OS_WIN 10 #include "src/base/win32-headers.h" 11 #endif 12 #include "src/base/logging.h" 13 14 #if V8_OS_POSIX 15 #include <pthread.h> // NOLINT 16 #endif 17 18 namespace v8 { 19 namespace base { 20 21 // ---------------------------------------------------------------------------- 22 // Mutex 23 // 24 // This class is a synchronization primitive that can be used to protect shared 25 // data from being simultaneously accessed by multiple threads. A mutex offers 26 // exclusive, non-recursive ownership semantics: 27 // - A calling thread owns a mutex from the time that it successfully calls 28 // either |Lock()| or |TryLock()| until it calls |Unlock()|. 29 // - When a thread owns a mutex, all other threads will block (for calls to 30 // |Lock()|) or receive a |false| return value (for |TryLock()|) if they 31 // attempt to claim ownership of the mutex. 32 // A calling thread must not own the mutex prior to calling |Lock()| or 33 // |TryLock()|. The behavior of a program is undefined if a mutex is destroyed 34 // while still owned by some thread. The Mutex class is non-copyable. 35 36 class Mutex final { 37 public: 38 Mutex(); 39 ~Mutex(); 40 41 // Locks the given mutex. If the mutex is currently unlocked, it becomes 42 // locked and owned by the calling thread, and immediately. If the mutex 43 // is already locked by another thread, suspends the calling thread until 44 // the mutex is unlocked. 45 void Lock(); 46 47 // Unlocks the given mutex. The mutex is assumed to be locked and owned by 48 // the calling thread on entrance. 49 void Unlock(); 50 51 // Tries to lock the given mutex. Returns whether the mutex was 52 // successfully locked. 53 bool TryLock() WARN_UNUSED_RESULT; 54 55 // The implementation-defined native handle type. 56 #if V8_OS_POSIX 57 typedef pthread_mutex_t NativeHandle; 58 #elif V8_OS_WIN 59 typedef CRITICAL_SECTION NativeHandle; 60 #endif 61 native_handle()62 NativeHandle& native_handle() { 63 return native_handle_; 64 } native_handle()65 const NativeHandle& native_handle() const { 66 return native_handle_; 67 } 68 69 private: 70 NativeHandle native_handle_; 71 #ifdef DEBUG 72 int level_; 73 #endif 74 AssertHeldAndUnmark()75 V8_INLINE void AssertHeldAndUnmark() { 76 #ifdef DEBUG 77 DCHECK_EQ(1, level_); 78 level_--; 79 #endif 80 } 81 AssertUnheldAndMark()82 V8_INLINE void AssertUnheldAndMark() { 83 #ifdef DEBUG 84 DCHECK_EQ(0, level_); 85 level_++; 86 #endif 87 } 88 89 friend class ConditionVariable; 90 91 DISALLOW_COPY_AND_ASSIGN(Mutex); 92 }; 93 94 95 // POD Mutex initialized lazily (i.e. the first time Pointer() is called). 96 // Usage: 97 // static LazyMutex my_mutex = LAZY_MUTEX_INITIALIZER; 98 // 99 // void my_function() { 100 // LockGuard<Mutex> guard(my_mutex.Pointer()); 101 // // Do something. 102 // } 103 // 104 typedef LazyStaticInstance<Mutex, DefaultConstructTrait<Mutex>, 105 ThreadSafeInitOnceTrait>::type LazyMutex; 106 107 #define LAZY_MUTEX_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER 108 109 110 // ----------------------------------------------------------------------------- 111 // RecursiveMutex 112 // 113 // This class is a synchronization primitive that can be used to protect shared 114 // data from being simultaneously accessed by multiple threads. A recursive 115 // mutex offers exclusive, recursive ownership semantics: 116 // - A calling thread owns a recursive mutex for a period of time that starts 117 // when it successfully calls either |Lock()| or |TryLock()|. During this 118 // period, the thread may make additional calls to |Lock()| or |TryLock()|. 119 // The period of ownership ends when the thread makes a matching number of 120 // calls to |Unlock()|. 121 // - When a thread owns a recursive mutex, all other threads will block (for 122 // calls to |Lock()|) or receive a |false| return value (for |TryLock()|) if 123 // they attempt to claim ownership of the recursive mutex. 124 // - The maximum number of times that a recursive mutex may be locked is 125 // unspecified, but after that number is reached, calls to |Lock()| will 126 // probably abort the process and calls to |TryLock()| return false. 127 // The behavior of a program is undefined if a recursive mutex is destroyed 128 // while still owned by some thread. The RecursiveMutex class is non-copyable. 129 130 class RecursiveMutex final { 131 public: 132 RecursiveMutex(); 133 ~RecursiveMutex(); 134 135 // Locks the mutex. If another thread has already locked the mutex, a call to 136 // |Lock()| will block execution until the lock is acquired. A thread may call 137 // |Lock()| on a recursive mutex repeatedly. Ownership will only be released 138 // after the thread makes a matching number of calls to |Unlock()|. 139 // The behavior is undefined if the mutex is not unlocked before being 140 // destroyed, i.e. some thread still owns it. 141 void Lock(); 142 143 // Unlocks the mutex if its level of ownership is 1 (there was exactly one 144 // more call to |Lock()| than there were calls to unlock() made by this 145 // thread), reduces the level of ownership by 1 otherwise. The mutex must be 146 // locked by the current thread of execution, otherwise, the behavior is 147 // undefined. 148 void Unlock(); 149 150 // Tries to lock the given mutex. Returns whether the mutex was 151 // successfully locked. 152 bool TryLock() WARN_UNUSED_RESULT; 153 154 // The implementation-defined native handle type. 155 typedef Mutex::NativeHandle NativeHandle; 156 native_handle()157 NativeHandle& native_handle() { 158 return native_handle_; 159 } native_handle()160 const NativeHandle& native_handle() const { 161 return native_handle_; 162 } 163 164 private: 165 NativeHandle native_handle_; 166 #ifdef DEBUG 167 int level_; 168 #endif 169 170 DISALLOW_COPY_AND_ASSIGN(RecursiveMutex); 171 }; 172 173 174 // POD RecursiveMutex initialized lazily (i.e. the first time Pointer() is 175 // called). 176 // Usage: 177 // static LazyRecursiveMutex my_mutex = LAZY_RECURSIVE_MUTEX_INITIALIZER; 178 // 179 // void my_function() { 180 // LockGuard<RecursiveMutex> guard(my_mutex.Pointer()); 181 // // Do something. 182 // } 183 // 184 typedef LazyStaticInstance<RecursiveMutex, 185 DefaultConstructTrait<RecursiveMutex>, 186 ThreadSafeInitOnceTrait>::type LazyRecursiveMutex; 187 188 #define LAZY_RECURSIVE_MUTEX_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER 189 190 191 // ----------------------------------------------------------------------------- 192 // LockGuard 193 // 194 // This class is a mutex wrapper that provides a convenient RAII-style mechanism 195 // for owning a mutex for the duration of a scoped block. 196 // When a LockGuard object is created, it attempts to take ownership of the 197 // mutex it is given. When control leaves the scope in which the LockGuard 198 // object was created, the LockGuard is destructed and the mutex is released. 199 // The LockGuard class is non-copyable. 200 201 template <typename Mutex> 202 class LockGuard final { 203 public: LockGuard(Mutex * mutex)204 explicit LockGuard(Mutex* mutex) : mutex_(mutex) { mutex_->Lock(); } ~LockGuard()205 ~LockGuard() { mutex_->Unlock(); } 206 207 private: 208 Mutex* mutex_; 209 210 DISALLOW_COPY_AND_ASSIGN(LockGuard); 211 }; 212 213 } // namespace base 214 } // namespace v8 215 216 #endif // V8_BASE_PLATFORM_MUTEX_H_ 217