Coverage Report

Created: 2025-08-03 10:06

/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_