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