• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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