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/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 
     62   NativeHandle& native_handle() {
     63     return native_handle_;
     64   }
     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 
     75   V8_INLINE void AssertHeldAndUnmark() {
     76 #ifdef DEBUG
     77     DCHECK_EQ(1, level_);
     78     level_--;
     79 #endif
     80   }
     81 
     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 
    157   NativeHandle& native_handle() {
    158     return native_handle_;
    159   }
    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:
    204   explicit LockGuard(Mutex* mutex) : mutex_(mutex) { mutex_->Lock(); }
    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