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
19namespace v8 {
20namespace 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
37class 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//
105typedef 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
131class 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//
185typedef 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
202template <typename Mutex>
203class 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