1 #ifndef SRC_NODE_MUTEX_H_
2 #define SRC_NODE_MUTEX_H_
3
4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6 #include "util.h"
7 #include "uv.h"
8
9 #include <memory> // std::shared_ptr<T>
10 #include <utility> // std::forward<T>
11
12 namespace node {
13
14 template <typename Traits> class ConditionVariableBase;
15 template <typename Traits> class MutexBase;
16 struct LibuvMutexTraits;
17 struct LibuvRwlockTraits;
18
19 using ConditionVariable = ConditionVariableBase<LibuvMutexTraits>;
20 using Mutex = MutexBase<LibuvMutexTraits>;
21 using RwLock = MutexBase<LibuvRwlockTraits>;
22
23 template <typename T, typename MutexT = Mutex>
24 class ExclusiveAccess {
25 public:
26 ExclusiveAccess() = default;
27
28 template <typename... Args>
ExclusiveAccess(Args &&...args)29 explicit ExclusiveAccess(Args&&... args)
30 : item_(std::forward<Args>(args)...) {}
31
32 ExclusiveAccess(const ExclusiveAccess&) = delete;
33 ExclusiveAccess& operator=(const ExclusiveAccess&) = delete;
34
35 class Scoped {
36 public:
37 // ExclusiveAccess will commonly be used in conjunction with std::shared_ptr
38 // and without this constructor it's too easy to forget to keep a reference
39 // around to the shared_ptr while operating on the ExclusiveAccess object.
Scoped(const std::shared_ptr<ExclusiveAccess> & shared)40 explicit Scoped(const std::shared_ptr<ExclusiveAccess>& shared)
41 : shared_(shared)
42 , scoped_lock_(shared->mutex_)
43 , pointer_(&shared->item_) {}
44
Scoped(ExclusiveAccess * exclusive_access)45 explicit Scoped(ExclusiveAccess* exclusive_access)
46 : shared_()
47 , scoped_lock_(exclusive_access->mutex_)
48 , pointer_(&exclusive_access->item_) {}
49
50 T& operator*() const { return *pointer_; }
51 T* operator->() const { return pointer_; }
52
53 Scoped(const Scoped&) = delete;
54 Scoped& operator=(const Scoped&) = delete;
55
56 private:
57 std::shared_ptr<ExclusiveAccess> shared_;
58 typename MutexT::ScopedLock scoped_lock_;
59 T* const pointer_;
60 };
61
62 private:
63 friend class ScopedLock;
64 MutexT mutex_;
65 T item_;
66 };
67
68 template <typename Traits>
69 class MutexBase {
70 public:
71 inline MutexBase();
72 inline ~MutexBase();
73 inline void Lock();
74 inline void Unlock();
75 inline void RdLock();
76 inline void RdUnlock();
77
78 MutexBase(const MutexBase&) = delete;
79 MutexBase& operator=(const MutexBase&) = delete;
80
81 class ScopedLock;
82 class ScopedUnlock;
83
84 class ScopedLock {
85 public:
86 inline explicit ScopedLock(const MutexBase& mutex);
87 inline explicit ScopedLock(const ScopedUnlock& scoped_unlock);
88 inline ~ScopedLock();
89
90 ScopedLock(const ScopedLock&) = delete;
91 ScopedLock& operator=(const ScopedLock&) = delete;
92
93 private:
94 template <typename> friend class ConditionVariableBase;
95 friend class ScopedUnlock;
96 const MutexBase& mutex_;
97 };
98
99 class ScopedReadLock {
100 public:
101 inline explicit ScopedReadLock(const MutexBase& mutex);
102 inline ~ScopedReadLock();
103
104 ScopedReadLock(const ScopedReadLock&) = delete;
105 ScopedReadLock& operator=(const ScopedReadLock&) = delete;
106
107 private:
108 template <typename> friend class ConditionVariableBase;
109 const MutexBase& mutex_;
110 };
111
112 using ScopedWriteLock = ScopedLock;
113
114 class ScopedUnlock {
115 public:
116 inline explicit ScopedUnlock(const ScopedLock& scoped_lock);
117 inline ~ScopedUnlock();
118
119 ScopedUnlock(const ScopedUnlock&) = delete;
120 ScopedUnlock& operator=(const ScopedUnlock&) = delete;
121
122 private:
123 friend class ScopedLock;
124 const MutexBase& mutex_;
125 };
126
127 private:
128 template <typename> friend class ConditionVariableBase;
129 mutable typename Traits::MutexT mutex_;
130 };
131
132 template <typename Traits>
133 class ConditionVariableBase {
134 public:
135 using ScopedLock = typename MutexBase<Traits>::ScopedLock;
136
137 inline ConditionVariableBase();
138 inline ~ConditionVariableBase();
139 inline void Broadcast(const ScopedLock&);
140 inline void Signal(const ScopedLock&);
141 inline void Wait(const ScopedLock& scoped_lock);
142
143 ConditionVariableBase(const ConditionVariableBase&) = delete;
144 ConditionVariableBase& operator=(const ConditionVariableBase&) = delete;
145
146 private:
147 typename Traits::CondT cond_;
148 };
149
150 struct LibuvMutexTraits {
151 using CondT = uv_cond_t;
152 using MutexT = uv_mutex_t;
153
cond_initLibuvMutexTraits154 static inline int cond_init(CondT* cond) {
155 return uv_cond_init(cond);
156 }
157
mutex_initLibuvMutexTraits158 static inline int mutex_init(MutexT* mutex) {
159 return uv_mutex_init(mutex);
160 }
161
cond_broadcastLibuvMutexTraits162 static inline void cond_broadcast(CondT* cond) {
163 uv_cond_broadcast(cond);
164 }
165
cond_destroyLibuvMutexTraits166 static inline void cond_destroy(CondT* cond) {
167 uv_cond_destroy(cond);
168 }
169
cond_signalLibuvMutexTraits170 static inline void cond_signal(CondT* cond) {
171 uv_cond_signal(cond);
172 }
173
cond_waitLibuvMutexTraits174 static inline void cond_wait(CondT* cond, MutexT* mutex) {
175 uv_cond_wait(cond, mutex);
176 }
177
mutex_destroyLibuvMutexTraits178 static inline void mutex_destroy(MutexT* mutex) {
179 uv_mutex_destroy(mutex);
180 }
181
mutex_lockLibuvMutexTraits182 static inline void mutex_lock(MutexT* mutex) {
183 uv_mutex_lock(mutex);
184 }
185
mutex_unlockLibuvMutexTraits186 static inline void mutex_unlock(MutexT* mutex) {
187 uv_mutex_unlock(mutex);
188 }
189
mutex_rdlockLibuvMutexTraits190 static inline void mutex_rdlock(MutexT* mutex) {
191 uv_mutex_lock(mutex);
192 }
193
mutex_rdunlockLibuvMutexTraits194 static inline void mutex_rdunlock(MutexT* mutex) {
195 uv_mutex_unlock(mutex);
196 }
197 };
198
199 struct LibuvRwlockTraits {
200 using MutexT = uv_rwlock_t;
201
mutex_initLibuvRwlockTraits202 static inline int mutex_init(MutexT* mutex) {
203 return uv_rwlock_init(mutex);
204 }
205
mutex_destroyLibuvRwlockTraits206 static inline void mutex_destroy(MutexT* mutex) {
207 uv_rwlock_destroy(mutex);
208 }
209
mutex_lockLibuvRwlockTraits210 static inline void mutex_lock(MutexT* mutex) {
211 uv_rwlock_wrlock(mutex);
212 }
213
mutex_unlockLibuvRwlockTraits214 static inline void mutex_unlock(MutexT* mutex) {
215 uv_rwlock_wrunlock(mutex);
216 }
217
mutex_rdlockLibuvRwlockTraits218 static inline void mutex_rdlock(MutexT* mutex) {
219 uv_rwlock_rdlock(mutex);
220 }
221
mutex_rdunlockLibuvRwlockTraits222 static inline void mutex_rdunlock(MutexT* mutex) {
223 uv_rwlock_rdunlock(mutex);
224 }
225 };
226
227 template <typename Traits>
ConditionVariableBase()228 ConditionVariableBase<Traits>::ConditionVariableBase() {
229 CHECK_EQ(0, Traits::cond_init(&cond_));
230 }
231
232 template <typename Traits>
~ConditionVariableBase()233 ConditionVariableBase<Traits>::~ConditionVariableBase() {
234 Traits::cond_destroy(&cond_);
235 }
236
237 template <typename Traits>
Broadcast(const ScopedLock &)238 void ConditionVariableBase<Traits>::Broadcast(const ScopedLock&) {
239 Traits::cond_broadcast(&cond_);
240 }
241
242 template <typename Traits>
Signal(const ScopedLock &)243 void ConditionVariableBase<Traits>::Signal(const ScopedLock&) {
244 Traits::cond_signal(&cond_);
245 }
246
247 template <typename Traits>
Wait(const ScopedLock & scoped_lock)248 void ConditionVariableBase<Traits>::Wait(const ScopedLock& scoped_lock) {
249 Traits::cond_wait(&cond_, &scoped_lock.mutex_.mutex_);
250 }
251
252 template <typename Traits>
MutexBase()253 MutexBase<Traits>::MutexBase() {
254 CHECK_EQ(0, Traits::mutex_init(&mutex_));
255 }
256
257 template <typename Traits>
~MutexBase()258 MutexBase<Traits>::~MutexBase() {
259 Traits::mutex_destroy(&mutex_);
260 }
261
262 template <typename Traits>
Lock()263 void MutexBase<Traits>::Lock() {
264 Traits::mutex_lock(&mutex_);
265 }
266
267 template <typename Traits>
Unlock()268 void MutexBase<Traits>::Unlock() {
269 Traits::mutex_unlock(&mutex_);
270 }
271
272 template <typename Traits>
RdLock()273 void MutexBase<Traits>::RdLock() {
274 Traits::mutex_rdlock(&mutex_);
275 }
276
277 template <typename Traits>
RdUnlock()278 void MutexBase<Traits>::RdUnlock() {
279 Traits::mutex_rdunlock(&mutex_);
280 }
281
282 template <typename Traits>
ScopedLock(const MutexBase & mutex)283 MutexBase<Traits>::ScopedLock::ScopedLock(const MutexBase& mutex)
284 : mutex_(mutex) {
285 Traits::mutex_lock(&mutex_.mutex_);
286 }
287
288 template <typename Traits>
ScopedLock(const ScopedUnlock & scoped_unlock)289 MutexBase<Traits>::ScopedLock::ScopedLock(const ScopedUnlock& scoped_unlock)
290 : MutexBase(scoped_unlock.mutex_) {}
291
292 template <typename Traits>
~ScopedLock()293 MutexBase<Traits>::ScopedLock::~ScopedLock() {
294 Traits::mutex_unlock(&mutex_.mutex_);
295 }
296
297 template <typename Traits>
ScopedReadLock(const MutexBase & mutex)298 MutexBase<Traits>::ScopedReadLock::ScopedReadLock(const MutexBase& mutex)
299 : mutex_(mutex) {
300 Traits::mutex_rdlock(&mutex_.mutex_);
301 }
302
303 template <typename Traits>
~ScopedReadLock()304 MutexBase<Traits>::ScopedReadLock::~ScopedReadLock() {
305 Traits::mutex_rdunlock(&mutex_.mutex_);
306 }
307
308 template <typename Traits>
ScopedUnlock(const ScopedLock & scoped_lock)309 MutexBase<Traits>::ScopedUnlock::ScopedUnlock(const ScopedLock& scoped_lock)
310 : mutex_(scoped_lock.mutex_) {
311 Traits::mutex_unlock(&mutex_.mutex_);
312 }
313
314 template <typename Traits>
~ScopedUnlock()315 MutexBase<Traits>::ScopedUnlock::~ScopedUnlock() {
316 Traits::mutex_lock(&mutex_.mutex_);
317 }
318
319 } // namespace node
320
321 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
322
323 #endif // SRC_NODE_MUTEX_H_
324