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