GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_mutex.h Lines: 90 90 100.0 %
Date: 2022-08-21 04:19:51 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
6125
  explicit ExclusiveAccess(Args&&... args)
30
6125
      : 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
378
    explicit Scoped(const std::shared_ptr<ExclusiveAccess>& shared)
41
        : shared_(shared)
42
756
        , scoped_lock_(shared->mutex_)
43
378
        , 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
461
    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
63298
  static inline int cond_init(CondT* cond) {
155
63298
    return uv_cond_init(cond);
156
  }
157
158
222252
  static inline int mutex_init(MutexT* mutex) {
159
222252
    return uv_mutex_init(mutex);
160
  }
161
162
64829
  static inline void cond_broadcast(CondT* cond) {
163
64829
    uv_cond_broadcast(cond);
164
64829
  }
165
166
41243
  static inline void cond_destroy(CondT* cond) {
167
41243
    uv_cond_destroy(cond);
168
41243
  }
169
170
237596
  static inline void cond_signal(CondT* cond) {
171
237596
    uv_cond_signal(cond);
172
237596
  }
173
174
191094
  static inline void cond_wait(CondT* cond, MutexT* mutex) {
175
191094
    uv_cond_wait(cond, mutex);
176
191066
  }
177
178
207958
  static inline void mutex_destroy(MutexT* mutex) {
179
207958
    uv_mutex_destroy(mutex);
180
207958
  }
181
182
6509389
  static inline void mutex_lock(MutexT* mutex) {
183
6509389
    uv_mutex_lock(mutex);
184
6509389
  }
185
186
6509361
  static inline void mutex_unlock(MutexT* mutex) {
187
6509361
    uv_mutex_unlock(mutex);
188
6509361
  }
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
12086
  static inline int mutex_init(MutexT* mutex) {
203
12086
    return uv_rwlock_init(mutex);
204
  }
205
206
12060
  static inline void mutex_destroy(MutexT* mutex) {
207
12060
    uv_rwlock_destroy(mutex);
208
12060
  }
209
210
36287
  static inline void mutex_lock(MutexT* mutex) {
211
36287
    uv_rwlock_wrlock(mutex);
212
36287
  }
213
214
36287
  static inline void mutex_unlock(MutexT* mutex) {
215
36287
    uv_rwlock_wrunlock(mutex);
216
36287
  }
217
218
76461
  static inline void mutex_rdlock(MutexT* mutex) {
219
76461
    uv_rwlock_rdlock(mutex);
220
76461
  }
221
222
76461
  static inline void mutex_rdunlock(MutexT* mutex) {
223
76461
    uv_rwlock_rdunlock(mutex);
224
76461
  }
225
};
226
227
template <typename Traits>
228
63298
ConditionVariableBase<Traits>::ConditionVariableBase() {
229
63298
  CHECK_EQ(0, Traits::cond_init(&cond_));
230
63298
}
231
232
template <typename Traits>
233
41243
ConditionVariableBase<Traits>::~ConditionVariableBase() {
234
41243
  Traits::cond_destroy(&cond_);
235
41243
}
236
237
template <typename Traits>
238
64829
void ConditionVariableBase<Traits>::Broadcast(const ScopedLock&) {
239
64829
  Traits::cond_broadcast(&cond_);
240
64829
}
241
242
template <typename Traits>
243
237596
void ConditionVariableBase<Traits>::Signal(const ScopedLock&) {
244
237596
  Traits::cond_signal(&cond_);
245
237596
}
246
247
template <typename Traits>
248
191094
void ConditionVariableBase<Traits>::Wait(const ScopedLock& scoped_lock) {
249
191094
  Traits::cond_wait(&cond_, &scoped_lock.mutex_.mutex_);
250
191066
}
251
252
template <typename Traits>
253
246424
MutexBase<Traits>::MutexBase() {
254
246424
  CHECK_EQ(0, Traits::mutex_init(&mutex_));
255
246424
}
256
257
template <typename Traits>
258
232078
MutexBase<Traits>::~MutexBase() {
259
232078
  Traits::mutex_destroy(&mutex_);
260
232078
}
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
6581807
MutexBase<Traits>::ScopedLock::ScopedLock(const MutexBase& mutex)
284
6581807
    : mutex_(mutex) {
285
6581807
  Traits::mutex_lock(&mutex_.mutex_);
286
6581807
}
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
6581779
MutexBase<Traits>::ScopedLock::~ScopedLock() {
294
6581779
  Traits::mutex_unlock(&mutex_.mutex_);
295
6581779
}
296
297
template <typename Traits>
298
76461
MutexBase<Traits>::ScopedReadLock::ScopedReadLock(const MutexBase& mutex)
299
76461
    : mutex_(mutex) {
300
76461
  Traits::mutex_rdlock(&mutex_.mutex_);
301
76461
}
302
303
template <typename Traits>
304
76461
MutexBase<Traits>::ScopedReadLock::~ScopedReadLock() {
305
76461
  Traits::mutex_rdunlock(&mutex_.mutex_);
306
76461
}
307
308
template <typename Traits>
309
156
MutexBase<Traits>::ScopedUnlock::ScopedUnlock(const ScopedLock& scoped_lock)
310
156
    : mutex_(scoped_lock.mutex_) {
311
156
  Traits::mutex_unlock(&mutex_.mutex_);
312
156
}
313
314
template <typename Traits>
315
156
MutexBase<Traits>::ScopedUnlock::~ScopedUnlock() {
316
156
  Traits::mutex_lock(&mutex_.mutex_);
317
156
}
318
319
}  // namespace node
320
321
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
322
323
#endif  // SRC_NODE_MUTEX_H_