• 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 
18 using ConditionVariable = ConditionVariableBase<LibuvMutexTraits>;
19 using Mutex = MutexBase<LibuvMutexTraits>;
20 
21 template <typename T, typename MutexT = Mutex>
22 class ExclusiveAccess {
23  public:
24   ExclusiveAccess() = default;
25 
26   template <typename... Args>
ExclusiveAccess(Args &&...args)27   explicit ExclusiveAccess(Args&&... args)
28       : item_(std::forward<Args>(args)...) {}
29 
30   ExclusiveAccess(const ExclusiveAccess&) = delete;
31   ExclusiveAccess& operator=(const ExclusiveAccess&) = delete;
32 
33   class Scoped {
34    public:
35     // ExclusiveAccess will commonly be used in conjunction with std::shared_ptr
36     // and without this constructor it's too easy to forget to keep a reference
37     // around to the shared_ptr while operating on the ExclusiveAccess object.
Scoped(const std::shared_ptr<ExclusiveAccess> & shared)38     explicit Scoped(const std::shared_ptr<ExclusiveAccess>& shared)
39         : shared_(shared)
40         , scoped_lock_(shared->mutex_)
41         , pointer_(&shared->item_) {}
42 
Scoped(ExclusiveAccess * exclusive_access)43     explicit Scoped(ExclusiveAccess* exclusive_access)
44         : shared_()
45         , scoped_lock_(exclusive_access->mutex_)
46         , pointer_(&exclusive_access->item_) {}
47 
48     T& operator*() const { return *pointer_; }
49     T* operator->() const { return pointer_; }
50 
51     Scoped(const Scoped&) = delete;
52     Scoped& operator=(const Scoped&) = delete;
53 
54    private:
55     std::shared_ptr<ExclusiveAccess> shared_;
56     typename MutexT::ScopedLock scoped_lock_;
57     T* const pointer_;
58   };
59 
60  private:
61   friend class ScopedLock;
62   MutexT mutex_;
63   T item_;
64 };
65 
66 template <typename Traits>
67 class MutexBase {
68  public:
69   inline MutexBase();
70   inline ~MutexBase();
71   inline void Lock();
72   inline void Unlock();
73 
74   MutexBase(const MutexBase&) = delete;
75   MutexBase& operator=(const MutexBase&) = delete;
76 
77   class ScopedLock;
78   class ScopedUnlock;
79 
80   class ScopedLock {
81    public:
82     inline explicit ScopedLock(const MutexBase& mutex);
83     inline explicit ScopedLock(const ScopedUnlock& scoped_unlock);
84     inline ~ScopedLock();
85 
86     ScopedLock(const ScopedLock&) = delete;
87     ScopedLock& operator=(const ScopedLock&) = delete;
88 
89    private:
90     template <typename> friend class ConditionVariableBase;
91     friend class ScopedUnlock;
92     const MutexBase& mutex_;
93   };
94 
95   class ScopedUnlock {
96    public:
97     inline explicit ScopedUnlock(const ScopedLock& scoped_lock);
98     inline ~ScopedUnlock();
99 
100     ScopedUnlock(const ScopedUnlock&) = delete;
101     ScopedUnlock& operator=(const ScopedUnlock&) = delete;
102 
103    private:
104     friend class ScopedLock;
105     const MutexBase& mutex_;
106   };
107 
108  private:
109   template <typename> friend class ConditionVariableBase;
110   mutable typename Traits::MutexT mutex_;
111 };
112 
113 template <typename Traits>
114 class ConditionVariableBase {
115  public:
116   using ScopedLock = typename MutexBase<Traits>::ScopedLock;
117 
118   inline ConditionVariableBase();
119   inline ~ConditionVariableBase();
120   inline void Broadcast(const ScopedLock&);
121   inline void Signal(const ScopedLock&);
122   inline void Wait(const ScopedLock& scoped_lock);
123 
124   ConditionVariableBase(const ConditionVariableBase&) = delete;
125   ConditionVariableBase& operator=(const ConditionVariableBase&) = delete;
126 
127  private:
128   typename Traits::CondT cond_;
129 };
130 
131 struct LibuvMutexTraits {
132   using CondT = uv_cond_t;
133   using MutexT = uv_mutex_t;
134 
cond_initLibuvMutexTraits135   static inline int cond_init(CondT* cond) {
136     return uv_cond_init(cond);
137   }
138 
mutex_initLibuvMutexTraits139   static inline int mutex_init(MutexT* mutex) {
140     return uv_mutex_init(mutex);
141   }
142 
cond_broadcastLibuvMutexTraits143   static inline void cond_broadcast(CondT* cond) {
144     uv_cond_broadcast(cond);
145   }
146 
cond_destroyLibuvMutexTraits147   static inline void cond_destroy(CondT* cond) {
148     uv_cond_destroy(cond);
149   }
150 
cond_signalLibuvMutexTraits151   static inline void cond_signal(CondT* cond) {
152     uv_cond_signal(cond);
153   }
154 
cond_waitLibuvMutexTraits155   static inline void cond_wait(CondT* cond, MutexT* mutex) {
156     uv_cond_wait(cond, mutex);
157   }
158 
mutex_destroyLibuvMutexTraits159   static inline void mutex_destroy(MutexT* mutex) {
160     uv_mutex_destroy(mutex);
161   }
162 
mutex_lockLibuvMutexTraits163   static inline void mutex_lock(MutexT* mutex) {
164     uv_mutex_lock(mutex);
165   }
166 
mutex_unlockLibuvMutexTraits167   static inline void mutex_unlock(MutexT* mutex) {
168     uv_mutex_unlock(mutex);
169   }
170 };
171 
172 template <typename Traits>
ConditionVariableBase()173 ConditionVariableBase<Traits>::ConditionVariableBase() {
174   CHECK_EQ(0, Traits::cond_init(&cond_));
175 }
176 
177 template <typename Traits>
~ConditionVariableBase()178 ConditionVariableBase<Traits>::~ConditionVariableBase() {
179   Traits::cond_destroy(&cond_);
180 }
181 
182 template <typename Traits>
Broadcast(const ScopedLock &)183 void ConditionVariableBase<Traits>::Broadcast(const ScopedLock&) {
184   Traits::cond_broadcast(&cond_);
185 }
186 
187 template <typename Traits>
Signal(const ScopedLock &)188 void ConditionVariableBase<Traits>::Signal(const ScopedLock&) {
189   Traits::cond_signal(&cond_);
190 }
191 
192 template <typename Traits>
Wait(const ScopedLock & scoped_lock)193 void ConditionVariableBase<Traits>::Wait(const ScopedLock& scoped_lock) {
194   Traits::cond_wait(&cond_, &scoped_lock.mutex_.mutex_);
195 }
196 
197 template <typename Traits>
MutexBase()198 MutexBase<Traits>::MutexBase() {
199   CHECK_EQ(0, Traits::mutex_init(&mutex_));
200 }
201 
202 template <typename Traits>
~MutexBase()203 MutexBase<Traits>::~MutexBase() {
204   Traits::mutex_destroy(&mutex_);
205 }
206 
207 template <typename Traits>
Lock()208 void MutexBase<Traits>::Lock() {
209   Traits::mutex_lock(&mutex_);
210 }
211 
212 template <typename Traits>
Unlock()213 void MutexBase<Traits>::Unlock() {
214   Traits::mutex_unlock(&mutex_);
215 }
216 
217 template <typename Traits>
ScopedLock(const MutexBase & mutex)218 MutexBase<Traits>::ScopedLock::ScopedLock(const MutexBase& mutex)
219     : mutex_(mutex) {
220   Traits::mutex_lock(&mutex_.mutex_);
221 }
222 
223 template <typename Traits>
ScopedLock(const ScopedUnlock & scoped_unlock)224 MutexBase<Traits>::ScopedLock::ScopedLock(const ScopedUnlock& scoped_unlock)
225     : MutexBase(scoped_unlock.mutex_) {}
226 
227 template <typename Traits>
~ScopedLock()228 MutexBase<Traits>::ScopedLock::~ScopedLock() {
229   Traits::mutex_unlock(&mutex_.mutex_);
230 }
231 
232 template <typename Traits>
ScopedUnlock(const ScopedLock & scoped_lock)233 MutexBase<Traits>::ScopedUnlock::ScopedUnlock(const ScopedLock& scoped_lock)
234     : mutex_(scoped_lock.mutex_) {
235   Traits::mutex_unlock(&mutex_.mutex_);
236 }
237 
238 template <typename Traits>
~ScopedUnlock()239 MutexBase<Traits>::ScopedUnlock::~ScopedUnlock() {
240   Traits::mutex_lock(&mutex_.mutex_);
241 }
242 
243 }  // namespace node
244 
245 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
246 
247 #endif  // SRC_NODE_MUTEX_H_
248