GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_mutex.h Lines: 90 90 100.0 %
Date: 2022-05-22 04:15:48 Branches: 2 4 50.0 %

Line Branch Exec Source
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
6026
  explicit ExclusiveAccess(Args&&... args)
30
6026
      : 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
326
    explicit Scoped(const std::shared_ptr<ExclusiveAccess>& shared)
41
        : shared_(shared)
42
652
        , scoped_lock_(shared->mutex_)
43
326
        , 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
409
    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
61738
  static inline int cond_init(CondT* cond) {
155
61738
    return uv_cond_init(cond);
156
  }
157
158
205913
  static inline int mutex_init(MutexT* mutex) {
159
205913
    return uv_mutex_init(mutex);
160
  }
161
162
62010
  static inline void cond_broadcast(CondT* cond) {
163
62010
    uv_cond_broadcast(cond);
164
62010
  }
165
166
40327
  static inline void cond_destroy(CondT* cond) {
167
40327
    uv_cond_destroy(cond);
168
40327
  }
169
170
232803
  static inline void cond_signal(CondT* cond) {
171
232803
    uv_cond_signal(cond);
172
232803
  }
173
174
185586
  static inline void cond_wait(CondT* cond, MutexT* mutex) {
175
185586
    uv_cond_wait(cond, mutex);
176
185558
  }
177
178
191718
  static inline void mutex_destroy(MutexT* mutex) {
179
191718
    uv_mutex_destroy(mutex);
180
191718
  }
181
182
6350806
  static inline void mutex_lock(MutexT* mutex) {
183
6350806
    uv_mutex_lock(mutex);
184
6350806
  }
185
186
6350778
  static inline void mutex_unlock(MutexT* mutex) {
187
6350778
    uv_mutex_unlock(mutex);
188
6350778
  }
189
190
  static inline void mutex_rdlock(MutexT* mutex) {
191
    uv_mutex_lock(mutex);
192
  }
193
194
  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
202
12228
  static inline int mutex_init(MutexT* mutex) {
203
12228
    return uv_rwlock_init(mutex);
204
  }
205
206
12204
  static inline void mutex_destroy(MutexT* mutex) {
207
12204
    uv_rwlock_destroy(mutex);
208
12204
  }
209
210
36715
  static inline void mutex_lock(MutexT* mutex) {
211
36715
    uv_rwlock_wrlock(mutex);
212
36715
  }
213
214
36715
  static inline void mutex_unlock(MutexT* mutex) {
215
36715
    uv_rwlock_wrunlock(mutex);
216
36715
  }
217
218
61754
  static inline void mutex_rdlock(MutexT* mutex) {
219
61754
    uv_rwlock_rdlock(mutex);
220
61754
  }
221
222
61754
  static inline void mutex_rdunlock(MutexT* mutex) {
223
61754
    uv_rwlock_rdunlock(mutex);
224
61754
  }
225
};
226
227
template <typename Traits>
228
61738
ConditionVariableBase<Traits>::ConditionVariableBase() {
229
61738
  CHECK_EQ(0, Traits::cond_init(&cond_));
230
61738
}
231
232
template <typename Traits>
233
40327
ConditionVariableBase<Traits>::~ConditionVariableBase() {
234
40327
  Traits::cond_destroy(&cond_);
235
40327
}
236
237
template <typename Traits>
238
62010
void ConditionVariableBase<Traits>::Broadcast(const ScopedLock&) {
239
62010
  Traits::cond_broadcast(&cond_);
240
62010
}
241
242
template <typename Traits>
243
232803
void ConditionVariableBase<Traits>::Signal(const ScopedLock&) {
244
232803
  Traits::cond_signal(&cond_);
245
232803
}
246
247
template <typename Traits>
248
185586
void ConditionVariableBase<Traits>::Wait(const ScopedLock& scoped_lock) {
249
185586
  Traits::cond_wait(&cond_, &scoped_lock.mutex_.mutex_);
250
185558
}
251
252
template <typename Traits>
253
230369
MutexBase<Traits>::MutexBase() {
254
230369
  CHECK_EQ(0, Traits::mutex_init(&mutex_));
255
230369
}
256
257
template <typename Traits>
258
216126
MutexBase<Traits>::~MutexBase() {
259
216126
  Traits::mutex_destroy(&mutex_);
260
216126
}
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
6424084
MutexBase<Traits>::ScopedLock::ScopedLock(const MutexBase& mutex)
284
6424084
    : mutex_(mutex) {
285
6424084
  Traits::mutex_lock(&mutex_.mutex_);
286
6424084
}
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
6424056
MutexBase<Traits>::ScopedLock::~ScopedLock() {
294
6424056
  Traits::mutex_unlock(&mutex_.mutex_);
295
6424056
}
296
297
template <typename Traits>
298
61754
MutexBase<Traits>::ScopedReadLock::ScopedReadLock(const MutexBase& mutex)
299
61754
    : mutex_(mutex) {
300
61754
  Traits::mutex_rdlock(&mutex_.mutex_);
301
61754
}
302
303
template <typename Traits>
304
61754
MutexBase<Traits>::ScopedReadLock::~ScopedReadLock() {
305
61754
  Traits::mutex_rdunlock(&mutex_.mutex_);
306
61754
}
307
308
template <typename Traits>
309
152
MutexBase<Traits>::ScopedUnlock::ScopedUnlock(const ScopedLock& scoped_lock)
310
152
    : mutex_(scoped_lock.mutex_) {
311
152
  Traits::mutex_unlock(&mutex_.mutex_);
312
152
}
313
314
template <typename Traits>
315
152
MutexBase<Traits>::ScopedUnlock::~ScopedUnlock() {
316
152
  Traits::mutex_lock(&mutex_.mutex_);
317
152
}
318
319
}  // namespace node
320
321
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
322
323
#endif  // SRC_NODE_MUTEX_H_