Home | History | Annotate | Download | only in platform
      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