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
18namespace v8 {
19namespace 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
36class 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//
104typedef 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
130class 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//
184typedef 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
201template <typename Mutex>
202class 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 v8::base
214
215#endif  // V8_BASE_PLATFORM_MUTEX_H_
216