/src/node/src/node_mutex.h
Line | Count | Source (jump to first uncovered line) |
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> |
29 | | explicit ExclusiveAccess(Args&&... args) |
30 | 126k | : 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. |
40 | | explicit Scoped(const std::shared_ptr<ExclusiveAccess>& shared) |
41 | 0 | : shared_(shared) |
42 | 0 | , scoped_lock_(shared->mutex_) |
43 | 0 | , pointer_(&shared->item_) {} |
44 | | |
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 | 0 | 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 | | |
154 | 1.26M | static inline int cond_init(CondT* cond) { |
155 | 1.26M | return uv_cond_init(cond); |
156 | 1.26M | } |
157 | | |
158 | 3.28M | static inline int mutex_init(MutexT* mutex) { |
159 | 3.28M | return uv_mutex_init(mutex); |
160 | 3.28M | } |
161 | | |
162 | 1.97M | static inline void cond_broadcast(CondT* cond) { |
163 | 1.97M | uv_cond_broadcast(cond); |
164 | 1.97M | } |
165 | | |
166 | 633k | static inline void cond_destroy(CondT* cond) { |
167 | 633k | uv_cond_destroy(cond); |
168 | 633k | } |
169 | | |
170 | 4.04M | static inline void cond_signal(CondT* cond) { |
171 | 4.04M | uv_cond_signal(cond); |
172 | 4.04M | } |
173 | | |
174 | 3.52M | static inline void cond_wait(CondT* cond, MutexT* mutex) { |
175 | 3.52M | uv_cond_wait(cond, mutex); |
176 | 3.52M | } |
177 | | |
178 | 768k | static inline void mutex_destroy(MutexT* mutex) { |
179 | 768k | uv_mutex_destroy(mutex); |
180 | 768k | } |
181 | | |
182 | 15.3M | static inline void mutex_lock(MutexT* mutex) { |
183 | 15.3M | uv_mutex_lock(mutex); |
184 | 15.3M | } |
185 | | |
186 | 14.8M | static inline void mutex_unlock(MutexT* mutex) { |
187 | 14.8M | uv_mutex_unlock(mutex); |
188 | 14.8M | } |
189 | | |
190 | 0 | static inline void mutex_rdlock(MutexT* mutex) { |
191 | 0 | uv_mutex_lock(mutex); |
192 | 0 | } |
193 | | |
194 | 0 | static inline void mutex_rdunlock(MutexT* mutex) { |
195 | 0 | uv_mutex_unlock(mutex); |
196 | 0 | } |
197 | | }; |
198 | | |
199 | | struct LibuvRwlockTraits { |
200 | | using MutexT = uv_rwlock_t; |
201 | | |
202 | 379k | static inline int mutex_init(MutexT* mutex) { |
203 | 379k | return uv_rwlock_init(mutex); |
204 | 379k | } |
205 | | |
206 | 253k | static inline void mutex_destroy(MutexT* mutex) { |
207 | 253k | uv_rwlock_destroy(mutex); |
208 | 253k | } |
209 | | |
210 | 22.8M | static inline void mutex_lock(MutexT* mutex) { |
211 | 22.8M | uv_rwlock_wrlock(mutex); |
212 | 22.8M | } |
213 | | |
214 | 22.8M | static inline void mutex_unlock(MutexT* mutex) { |
215 | 22.8M | uv_rwlock_wrunlock(mutex); |
216 | 22.8M | } |
217 | | |
218 | 11.9M | static inline void mutex_rdlock(MutexT* mutex) { |
219 | 11.9M | uv_rwlock_rdlock(mutex); |
220 | 11.9M | } |
221 | | |
222 | 11.9M | static inline void mutex_rdunlock(MutexT* mutex) { |
223 | 11.9M | uv_rwlock_rdunlock(mutex); |
224 | 11.9M | } |
225 | | }; |
226 | | |
227 | | template <typename Traits> |
228 | 1.26M | ConditionVariableBase<Traits>::ConditionVariableBase() { |
229 | 1.26M | CHECK_EQ(0, Traits::cond_init(&cond_)); |
230 | 1.26M | } |
231 | | |
232 | | template <typename Traits> |
233 | 633k | ConditionVariableBase<Traits>::~ConditionVariableBase() { |
234 | 633k | Traits::cond_destroy(&cond_); |
235 | 633k | } |
236 | | |
237 | | template <typename Traits> |
238 | 1.97M | void ConditionVariableBase<Traits>::Broadcast(const ScopedLock&) { |
239 | 1.97M | Traits::cond_broadcast(&cond_); |
240 | 1.97M | } |
241 | | |
242 | | template <typename Traits> |
243 | 4.04M | void ConditionVariableBase<Traits>::Signal(const ScopedLock&) { |
244 | 4.04M | Traits::cond_signal(&cond_); |
245 | 4.04M | } |
246 | | |
247 | | template <typename Traits> |
248 | 3.52M | void ConditionVariableBase<Traits>::Wait(const ScopedLock& scoped_lock) { |
249 | 3.52M | Traits::cond_wait(&cond_, &scoped_lock.mutex_.mutex_); |
250 | 3.52M | } |
251 | | |
252 | | template <typename Traits> |
253 | 3.66M | MutexBase<Traits>::MutexBase() { |
254 | 3.66M | CHECK_EQ(0, Traits::mutex_init(&mutex_)); |
255 | 3.66M | } node::MutexBase<node::LibuvMutexTraits>::MutexBase() Line | Count | Source | 253 | 3.28M | MutexBase<Traits>::MutexBase() { | 254 | 3.28M | CHECK_EQ(0, Traits::mutex_init(&mutex_)); | 255 | 3.28M | } |
node::MutexBase<node::LibuvRwlockTraits>::MutexBase() Line | Count | Source | 253 | 379k | MutexBase<Traits>::MutexBase() { | 254 | 379k | CHECK_EQ(0, Traits::mutex_init(&mutex_)); | 255 | 379k | } |
|
256 | | |
257 | | template <typename Traits> |
258 | 1.02M | MutexBase<Traits>::~MutexBase() { |
259 | 1.02M | Traits::mutex_destroy(&mutex_); |
260 | 1.02M | } node::MutexBase<node::LibuvMutexTraits>::~MutexBase() Line | Count | Source | 258 | 768k | MutexBase<Traits>::~MutexBase() { | 259 | 768k | Traits::mutex_destroy(&mutex_); | 260 | 768k | } |
node::MutexBase<node::LibuvRwlockTraits>::~MutexBase() Line | Count | Source | 258 | 253k | MutexBase<Traits>::~MutexBase() { | 259 | 253k | Traits::mutex_destroy(&mutex_); | 260 | 253k | } |
|
261 | | |
262 | | template <typename Traits> |
263 | | void MutexBase<Traits>::Lock() { |
264 | | Traits::mutex_lock(&mutex_); |
265 | | } |
266 | | |
267 | | template <typename Traits> |
268 | | void MutexBase<Traits>::Unlock() { |
269 | | Traits::mutex_unlock(&mutex_); |
270 | | } |
271 | | |
272 | | template <typename Traits> |
273 | | void MutexBase<Traits>::RdLock() { |
274 | | Traits::mutex_rdlock(&mutex_); |
275 | | } |
276 | | |
277 | | template <typename Traits> |
278 | | void MutexBase<Traits>::RdUnlock() { |
279 | | Traits::mutex_rdunlock(&mutex_); |
280 | | } |
281 | | |
282 | | template <typename Traits> |
283 | | MutexBase<Traits>::ScopedLock::ScopedLock(const MutexBase& mutex) |
284 | 38.2M | : mutex_(mutex) { |
285 | 38.2M | Traits::mutex_lock(&mutex_.mutex_); |
286 | 38.2M | } node::MutexBase<node::LibuvMutexTraits>::ScopedLock::ScopedLock(node::MutexBase<node::LibuvMutexTraits> const&) Line | Count | Source | 284 | 15.3M | : mutex_(mutex) { | 285 | 15.3M | Traits::mutex_lock(&mutex_.mutex_); | 286 | 15.3M | } |
node::MutexBase<node::LibuvRwlockTraits>::ScopedLock::ScopedLock(node::MutexBase<node::LibuvRwlockTraits> const&) Line | Count | Source | 284 | 22.8M | : mutex_(mutex) { | 285 | 22.8M | Traits::mutex_lock(&mutex_.mutex_); | 286 | 22.8M | } |
|
287 | | |
288 | | template <typename Traits> |
289 | | MutexBase<Traits>::ScopedLock::ScopedLock(const ScopedUnlock& scoped_unlock) |
290 | | : MutexBase(scoped_unlock.mutex_) {} |
291 | | |
292 | | template <typename Traits> |
293 | 37.7M | MutexBase<Traits>::ScopedLock::~ScopedLock() { |
294 | 37.7M | Traits::mutex_unlock(&mutex_.mutex_); |
295 | 37.7M | } node::MutexBase<node::LibuvMutexTraits>::ScopedLock::~ScopedLock() Line | Count | Source | 293 | 14.8M | MutexBase<Traits>::ScopedLock::~ScopedLock() { | 294 | 14.8M | Traits::mutex_unlock(&mutex_.mutex_); | 295 | 14.8M | } |
node::MutexBase<node::LibuvRwlockTraits>::ScopedLock::~ScopedLock() Line | Count | Source | 293 | 22.8M | MutexBase<Traits>::ScopedLock::~ScopedLock() { | 294 | 22.8M | Traits::mutex_unlock(&mutex_.mutex_); | 295 | 22.8M | } |
|
296 | | |
297 | | template <typename Traits> |
298 | | MutexBase<Traits>::ScopedReadLock::ScopedReadLock(const MutexBase& mutex) |
299 | 11.9M | : mutex_(mutex) { |
300 | 11.9M | Traits::mutex_rdlock(&mutex_.mutex_); |
301 | 11.9M | } |
302 | | |
303 | | template <typename Traits> |
304 | 11.9M | MutexBase<Traits>::ScopedReadLock::~ScopedReadLock() { |
305 | 11.9M | Traits::mutex_rdunlock(&mutex_.mutex_); |
306 | 11.9M | } |
307 | | |
308 | | template <typename Traits> |
309 | | MutexBase<Traits>::ScopedUnlock::ScopedUnlock(const ScopedLock& scoped_lock) |
310 | 0 | : mutex_(scoped_lock.mutex_) { |
311 | 0 | Traits::mutex_unlock(&mutex_.mutex_); |
312 | 0 | } |
313 | | |
314 | | template <typename Traits> |
315 | 0 | MutexBase<Traits>::ScopedUnlock::~ScopedUnlock() { |
316 | 0 | Traits::mutex_lock(&mutex_.mutex_); |
317 | 0 | } |
318 | | |
319 | | } // namespace node |
320 | | |
321 | | #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
322 | | |
323 | | #endif // SRC_NODE_MUTEX_H_ |