1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_PLATFORM_MUTEX_H_ 29 #define V8_PLATFORM_MUTEX_H_ 30 31 #include "../lazy-instance.h" 32 #if V8_OS_WIN 33 #include "../win32-headers.h" 34 #endif 35 36 #if V8_OS_POSIX 37 #include <pthread.h> // NOLINT 38 #endif 39 40 namespace v8 { 41 namespace internal { 42 43 // ---------------------------------------------------------------------------- 44 // Mutex 45 // 46 // This class is a synchronization primitive that can be used to protect shared 47 // data from being simultaneously accessed by multiple threads. A mutex offers 48 // exclusive, non-recursive ownership semantics: 49 // - A calling thread owns a mutex from the time that it successfully calls 50 // either |Lock()| or |TryLock()| until it calls |Unlock()|. 51 // - When a thread owns a mutex, all other threads will block (for calls to 52 // |Lock()|) or receive a |false| return value (for |TryLock()|) if they 53 // attempt to claim ownership of the mutex. 54 // A calling thread must not own the mutex prior to calling |Lock()| or 55 // |TryLock()|. The behavior of a program is undefined if a mutex is destroyed 56 // while still owned by some thread. The Mutex class is non-copyable. 57 58 class Mutex V8_FINAL { 59 public: 60 Mutex(); 61 ~Mutex(); 62 63 // Locks the given mutex. If the mutex is currently unlocked, it becomes 64 // locked and owned by the calling thread, and immediately. If the mutex 65 // is already locked by another thread, suspends the calling thread until 66 // the mutex is unlocked. 67 void Lock(); 68 69 // Unlocks the given mutex. The mutex is assumed to be locked and owned by 70 // the calling thread on entrance. 71 void Unlock(); 72 73 // Tries to lock the given mutex. Returns whether the mutex was 74 // successfully locked. 75 bool TryLock() V8_WARN_UNUSED_RESULT; 76 77 // The implementation-defined native handle type. 78 #if V8_OS_POSIX 79 typedef pthread_mutex_t NativeHandle; 80 #elif V8_OS_WIN 81 typedef CRITICAL_SECTION NativeHandle; 82 #endif 83 84 NativeHandle& native_handle() { 85 return native_handle_; 86 } 87 const NativeHandle& native_handle() const { 88 return native_handle_; 89 } 90 91 private: 92 NativeHandle native_handle_; 93 #ifdef DEBUG 94 int level_; 95 #endif 96 97 V8_INLINE void AssertHeldAndUnmark() { 98 #ifdef DEBUG 99 ASSERT_EQ(1, level_); 100 level_--; 101 #endif 102 } 103 104 V8_INLINE void AssertUnheldAndMark() { 105 #ifdef DEBUG 106 ASSERT_EQ(0, level_); 107 level_++; 108 #endif 109 } 110 111 friend class ConditionVariable; 112 113 DISALLOW_COPY_AND_ASSIGN(Mutex); 114 }; 115 116 117 // POD Mutex initialized lazily (i.e. the first time Pointer() is called). 118 // Usage: 119 // static LazyMutex my_mutex = LAZY_MUTEX_INITIALIZER; 120 // 121 // void my_function() { 122 // LockGuard<Mutex> guard(my_mutex.Pointer()); 123 // // Do something. 124 // } 125 // 126 typedef LazyStaticInstance<Mutex, 127 DefaultConstructTrait<Mutex>, 128 ThreadSafeInitOnceTrait>::type LazyMutex; 129 130 #define LAZY_MUTEX_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER 131 132 133 // ----------------------------------------------------------------------------- 134 // RecursiveMutex 135 // 136 // This class is a synchronization primitive that can be used to protect shared 137 // data from being simultaneously accessed by multiple threads. A recursive 138 // mutex offers exclusive, recursive ownership semantics: 139 // - A calling thread owns a recursive mutex for a period of time that starts 140 // when it successfully calls either |Lock()| or |TryLock()|. During this 141 // period, the thread may make additional calls to |Lock()| or |TryLock()|. 142 // The period of ownership ends when the thread makes a matching number of 143 // calls to |Unlock()|. 144 // - When a thread owns a recursive mutex, all other threads will block (for 145 // calls to |Lock()|) or receive a |false| return value (for |TryLock()|) if 146 // they attempt to claim ownership of the recursive mutex. 147 // - The maximum number of times that a recursive mutex may be locked is 148 // unspecified, but after that number is reached, calls to |Lock()| will 149 // probably abort the process and calls to |TryLock()| return false. 150 // The behavior of a program is undefined if a recursive mutex is destroyed 151 // while still owned by some thread. The RecursiveMutex class is non-copyable. 152 153 class RecursiveMutex V8_FINAL { 154 public: 155 RecursiveMutex(); 156 ~RecursiveMutex(); 157 158 // Locks the mutex. If another thread has already locked the mutex, a call to 159 // |Lock()| will block execution until the lock is acquired. A thread may call 160 // |Lock()| on a recursive mutex repeatedly. Ownership will only be released 161 // after the thread makes a matching number of calls to |Unlock()|. 162 // The behavior is undefined if the mutex is not unlocked before being 163 // destroyed, i.e. some thread still owns it. 164 void Lock(); 165 166 // Unlocks the mutex if its level of ownership is 1 (there was exactly one 167 // more call to |Lock()| than there were calls to unlock() made by this 168 // thread), reduces the level of ownership by 1 otherwise. The mutex must be 169 // locked by the current thread of execution, otherwise, the behavior is 170 // undefined. 171 void Unlock(); 172 173 // Tries to lock the given mutex. Returns whether the mutex was 174 // successfully locked. 175 bool TryLock() V8_WARN_UNUSED_RESULT; 176 177 // The implementation-defined native handle type. 178 typedef Mutex::NativeHandle NativeHandle; 179 180 NativeHandle& native_handle() { 181 return native_handle_; 182 } 183 const NativeHandle& native_handle() const { 184 return native_handle_; 185 } 186 187 private: 188 NativeHandle native_handle_; 189 #ifdef DEBUG 190 int level_; 191 #endif 192 193 DISALLOW_COPY_AND_ASSIGN(RecursiveMutex); 194 }; 195 196 197 // POD RecursiveMutex initialized lazily (i.e. the first time Pointer() is 198 // called). 199 // Usage: 200 // static LazyRecursiveMutex my_mutex = LAZY_RECURSIVE_MUTEX_INITIALIZER; 201 // 202 // void my_function() { 203 // LockGuard<RecursiveMutex> guard(my_mutex.Pointer()); 204 // // Do something. 205 // } 206 // 207 typedef LazyStaticInstance<RecursiveMutex, 208 DefaultConstructTrait<RecursiveMutex>, 209 ThreadSafeInitOnceTrait>::type LazyRecursiveMutex; 210 211 #define LAZY_RECURSIVE_MUTEX_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER 212 213 214 // ----------------------------------------------------------------------------- 215 // LockGuard 216 // 217 // This class is a mutex wrapper that provides a convenient RAII-style mechanism 218 // for owning a mutex for the duration of a scoped block. 219 // When a LockGuard object is created, it attempts to take ownership of the 220 // mutex it is given. When control leaves the scope in which the LockGuard 221 // object was created, the LockGuard is destructed and the mutex is released. 222 // The LockGuard class is non-copyable. 223 224 template <typename Mutex> 225 class LockGuard V8_FINAL { 226 public: 227 explicit LockGuard(Mutex* mutex) : mutex_(mutex) { mutex_->Lock(); } 228 ~LockGuard() { mutex_->Unlock(); } 229 230 private: 231 Mutex* mutex_; 232 233 DISALLOW_COPY_AND_ASSIGN(LockGuard); 234 }; 235 236 } } // namespace v8::internal 237 238 #endif // V8_PLATFORM_MUTEX_H_ 239