LCOV - code coverage report
Current view: top level - src/base/platform - mutex.h (source / functions) Hit Total Coverage
Test: app.info Lines: 9 9 100.0 %
Date: 2019-04-17 Functions: 2 2 100.0 %

          Line data    Source code
       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 - a replacement for std::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() V8_WARN_UNUSED_RESULT;
      55             : 
      56             :   // The implementation-defined native handle type.
      57             : #if V8_OS_POSIX
      58             :   using NativeHandle = pthread_mutex_t;
      59             : #elif V8_OS_WIN
      60             :   using NativeHandle = SRWLOCK;
      61             : #endif
      62             : 
      63             :   NativeHandle& native_handle() {
      64     1957894 :     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             : // 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             : //     MutexGuard guard(my_mutex.Pointer());
     101             : //     // Do something.
     102             : //   }
     103             : //
     104             : using LazyMutex = LazyStaticInstance<Mutex, DefaultConstructTrait<Mutex>,
     105             :                                      ThreadSafeInitOnceTrait>::type;
     106             : 
     107             : #define LAZY_MUTEX_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
     108             : 
     109             : // -----------------------------------------------------------------------------
     110             : // RecursiveMutex - a replacement for std::recursive_mutex
     111             : //
     112             : // This class is a synchronization primitive that can be used to protect shared
     113             : // data from being simultaneously accessed by multiple threads. A recursive
     114             : // mutex offers exclusive, recursive ownership semantics:
     115             : // - A calling thread owns a recursive mutex for a period of time that starts
     116             : //   when it successfully calls either |Lock()| or |TryLock()|. During this
     117             : //   period, the thread may make additional calls to |Lock()| or |TryLock()|.
     118             : //   The period of ownership ends when the thread makes a matching number of
     119             : //   calls to |Unlock()|.
     120             : // - When a thread owns a recursive mutex, all other threads will block (for
     121             : //   calls to |Lock()|) or receive a |false| return value (for |TryLock()|) if
     122             : //   they attempt to claim ownership of the recursive mutex.
     123             : // - The maximum number of times that a recursive mutex may be locked is
     124             : //   unspecified, but after that number is reached, calls to |Lock()| will
     125             : //   probably abort the process and calls to |TryLock()| return false.
     126             : // The behavior of a program is undefined if a recursive mutex is destroyed
     127             : // while still owned by some thread. The RecursiveMutex class is non-copyable.
     128             : 
     129             : class V8_BASE_EXPORT RecursiveMutex final {
     130             :  public:
     131             :   RecursiveMutex();
     132             :   ~RecursiveMutex();
     133             : 
     134             :   // Locks the mutex. If another thread has already locked the mutex, a call to
     135             :   // |Lock()| will block execution until the lock is acquired. A thread may call
     136             :   // |Lock()| on a recursive mutex repeatedly. Ownership will only be released
     137             :   // after the thread makes a matching number of calls to |Unlock()|.
     138             :   // The behavior is undefined if the mutex is not unlocked before being
     139             :   // destroyed, i.e. some thread still owns it.
     140             :   void Lock();
     141             : 
     142             :   // Unlocks the mutex if its level of ownership is 1 (there was exactly one
     143             :   // more call to |Lock()| than there were calls to unlock() made by this
     144             :   // thread), reduces the level of ownership by 1 otherwise. The mutex must be
     145             :   // locked by the current thread of execution, otherwise, the behavior is
     146             :   // undefined.
     147             :   void Unlock();
     148             : 
     149             :   // Tries to lock the given mutex. Returns whether the mutex was
     150             :   // successfully locked.
     151             :   bool TryLock() V8_WARN_UNUSED_RESULT;
     152             : 
     153             :  private:
     154             :   // The implementation-defined native handle type.
     155             : #if V8_OS_POSIX
     156             :   using NativeHandle = pthread_mutex_t;
     157             : #elif V8_OS_WIN
     158             :   using NativeHandle = CRITICAL_SECTION;
     159             : #endif
     160             : 
     161             :   NativeHandle native_handle_;
     162             : #ifdef DEBUG
     163             :   int level_;
     164             : #endif
     165             : 
     166             :   DISALLOW_COPY_AND_ASSIGN(RecursiveMutex);
     167             : };
     168             : 
     169             : 
     170             : // POD RecursiveMutex initialized lazily (i.e. the first time Pointer() is
     171             : // called).
     172             : // Usage:
     173             : //   static LazyRecursiveMutex my_mutex = LAZY_RECURSIVE_MUTEX_INITIALIZER;
     174             : //
     175             : //   void my_function() {
     176             : //     LockGuard<RecursiveMutex> guard(my_mutex.Pointer());
     177             : //     // Do something.
     178             : //   }
     179             : //
     180             : using LazyRecursiveMutex =
     181             :     LazyStaticInstance<RecursiveMutex, DefaultConstructTrait<RecursiveMutex>,
     182             :                        ThreadSafeInitOnceTrait>::type;
     183             : 
     184             : #define LAZY_RECURSIVE_MUTEX_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
     185             : 
     186             : // ----------------------------------------------------------------------------
     187             : // SharedMutex - a replacement for std::shared_mutex
     188             : //
     189             : // This class is a synchronization primitive that can be used to protect shared
     190             : // data from being simultaneously accessed by multiple threads. In contrast to
     191             : // other mutex types which facilitate exclusive access, a shared_mutex has two
     192             : // levels of access:
     193             : // - shared: several threads can share ownership of the same mutex.
     194             : // - exclusive: only one thread can own the mutex.
     195             : // Shared mutexes are usually used in situations when multiple readers can
     196             : // access the same resource at the same time without causing data races, but
     197             : // only one writer can do so.
     198             : // The SharedMutex class is non-copyable.
     199             : 
     200             : class V8_BASE_EXPORT SharedMutex final {
     201             :  public:
     202             :   SharedMutex();
     203             :   ~SharedMutex();
     204             : 
     205             :   // Acquires shared ownership of the {SharedMutex}. If another thread is
     206             :   // holding the mutex in exclusive ownership, a call to {LockShared()} will
     207             :   // block execution until shared ownership can be acquired.
     208             :   // If {LockShared()} is called by a thread that already owns the mutex in any
     209             :   // mode (exclusive or shared), the behavior is undefined.
     210             :   void LockShared();
     211             : 
     212             :   // Locks the SharedMutex. If another thread has already locked the mutex, a
     213             :   // call to {LockExclusive()} will block execution until the lock is acquired.
     214             :   // If {LockExclusive()} is called by a thread that already owns the mutex in
     215             :   // any mode (shared or exclusive), the behavior is undefined.
     216             :   void LockExclusive();
     217             : 
     218             :   // Releases the {SharedMutex} from shared ownership by the calling thread.
     219             :   // The mutex must be locked by the current thread of execution in shared mode,
     220             :   // otherwise, the behavior is undefined.
     221             :   void UnlockShared();
     222             : 
     223             :   // Unlocks the {SharedMutex}. It must be locked by the current thread of
     224             :   // execution, otherwise, the behavior is undefined.
     225             :   void UnlockExclusive();
     226             : 
     227             :   // Tries to lock the {SharedMutex} in shared mode. Returns immediately. On
     228             :   // successful lock acquisition returns true, otherwise returns false.
     229             :   // This function is allowed to fail spuriously and return false even if the
     230             :   // mutex is not currenly exclusively locked by any other thread.
     231             :   bool TryLockShared() V8_WARN_UNUSED_RESULT;
     232             : 
     233             :   // Tries to lock the {SharedMutex}. Returns immediately. On successful lock
     234             :   // acquisition returns true, otherwise returns false.
     235             :   // This function is allowed to fail spuriously and return false even if the
     236             :   // mutex is not currently locked by any other thread.
     237             :   // If try_lock is called by a thread that already owns the mutex in any mode
     238             :   // (shared or exclusive), the behavior is undefined.
     239             :   bool TryLockExclusive() V8_WARN_UNUSED_RESULT;
     240             : 
     241             :  private:
     242             :   // The implementation-defined native handle type.
     243             : #if V8_OS_POSIX
     244             :   using NativeHandle = pthread_rwlock_t;
     245             : #elif V8_OS_WIN
     246             :   using NativeHandle = SRWLOCK;
     247             : #endif
     248             : 
     249             :   NativeHandle native_handle_;
     250             : 
     251             :   DISALLOW_COPY_AND_ASSIGN(SharedMutex);
     252             : };
     253             : 
     254             : // -----------------------------------------------------------------------------
     255             : // LockGuard
     256             : //
     257             : // This class is a mutex wrapper that provides a convenient RAII-style mechanism
     258             : // for owning a mutex for the duration of a scoped block.
     259             : // When a LockGuard object is created, it attempts to take ownership of the
     260             : // mutex it is given. When control leaves the scope in which the LockGuard
     261             : // object was created, the LockGuard is destructed and the mutex is released.
     262             : // The LockGuard class is non-copyable.
     263             : 
     264             : // Controls whether a LockGuard always requires a valid Mutex or will just
     265             : // ignore it if it's nullptr.
     266             : enum class NullBehavior { kRequireNotNull, kIgnoreIfNull };
     267             : 
     268             : template <typename Mutex, NullBehavior Behavior = NullBehavior::kRequireNotNull>
     269             : class LockGuard final {
     270             :  public:
     271      293663 :   explicit LockGuard(Mutex* mutex) : mutex_(mutex) {
     272   205422255 :     if (has_mutex()) mutex_->Lock();
     273          17 :   }
     274          17 :   ~LockGuard() {
     275   205022094 :     if (has_mutex()) mutex_->Unlock();
     276      293663 :   }
     277             : 
     278             :  private:
     279             :   Mutex* const mutex_;
     280             : 
     281             :   bool V8_INLINE has_mutex() const {
     282             :     DCHECK_IMPLIES(Behavior == NullBehavior::kRequireNotNull,
     283             :                    mutex_ != nullptr);
     284             :     return Behavior == NullBehavior::kRequireNotNull || mutex_ != nullptr;
     285             :   }
     286             : 
     287             :   DISALLOW_COPY_AND_ASSIGN(LockGuard);
     288             : };
     289             : 
     290             : using MutexGuard = LockGuard<Mutex>;
     291             : 
     292             : enum MutexSharedType : bool { kShared = true, kExclusive = false };
     293             : 
     294             : template <MutexSharedType kIsShared,
     295             :           NullBehavior Behavior = NullBehavior::kRequireNotNull>
     296             : class SharedMutexGuard final {
     297             :  public:
     298             :   explicit SharedMutexGuard(SharedMutex* mutex) : mutex_(mutex) {
     299             :     if (!has_mutex()) return;
     300             :     if (kIsShared) {
     301             :       mutex_->LockShared();
     302             :     } else {
     303     1250461 :       mutex_->LockExclusive();
     304             :     }
     305             :   }
     306             :   ~SharedMutexGuard() {
     307             :     if (!has_mutex()) return;
     308             :     if (kIsShared) {
     309             :       mutex_->UnlockShared();
     310             :     } else {
     311     1250464 :       mutex_->UnlockExclusive();
     312             :     }
     313             :   }
     314             : 
     315             :  private:
     316             :   SharedMutex* const mutex_;
     317             : 
     318             :   bool V8_INLINE has_mutex() const {
     319             :     DCHECK_IMPLIES(Behavior == NullBehavior::kRequireNotNull,
     320             :                    mutex_ != nullptr);
     321             :     return Behavior == NullBehavior::kRequireNotNull || mutex_ != nullptr;
     322             :   }
     323             : 
     324             :   DISALLOW_COPY_AND_ASSIGN(SharedMutexGuard);
     325             : };
     326             : 
     327             : }  // namespace base
     328             : }  // namespace v8
     329             : 
     330             : #endif  // V8_BASE_PLATFORM_MUTEX_H_

Generated by: LCOV version 1.10