1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef SRC_JSVM_MUTEX_H_
17 #define SRC_JSVM_MUTEX_H_
18
19 #include <memory> // std::shared_ptr<T>
20 #include <utility> // std::forward<T>
21
22 #include "jsvm_util.h"
23 #include "uv.h"
24
25 namespace jsvm {
26
27 template<typename Traits>
28 class ConditionVariableBase;
29 template<typename Traits>
30 class MutexBase;
31 struct LibuvMutexTraits;
32 struct LibuvRwlockTraits;
33
34 using ConditionVariable = ConditionVariableBase<LibuvMutexTraits>;
35 using Mutex = MutexBase<LibuvMutexTraits>;
36 using RwLock = MutexBase<LibuvRwlockTraits>;
37
38 template<typename T, typename MutexT = Mutex>
39 class ExclusiveAccess {
40 public:
41 ExclusiveAccess() = default;
42
43 template<typename... Args>
ExclusiveAccess(Args &&...args)44 explicit ExclusiveAccess(Args&&... args) : item(std::forward<Args>(args)...)
45 {}
46
47 ExclusiveAccess(const ExclusiveAccess&) = delete;
48 ExclusiveAccess& operator=(const ExclusiveAccess&) = delete;
49
50 class Scoped {
51 public:
52 // ExclusiveAccess will commonly be used in conjunction with std::shared_ptr
53 // and without this constructor it's too easy to forget to keep a reference
54 // around to the shared_ptr while operating on the ExclusiveAccess object.
Scoped(const std::shared_ptr<ExclusiveAccess> & shared)55 explicit Scoped(const std::shared_ptr<ExclusiveAccess>& shared)
56 : shared(shared), scopedLock(shared->mutex), pointer(&shared->item)
57 {}
58
Scoped(ExclusiveAccess * exclusiveAccess)59 explicit Scoped(ExclusiveAccess* exclusiveAccess)
60 : shared(), scopedLock(exclusiveAccess->mutex), pointer(&exclusiveAccess->item)
61 {}
62
63 T& operator*() const
64 {
65 return *pointer;
66 }
67 T* operator->() const
68 {
69 return pointer;
70 }
71
72 Scoped(const Scoped&) = delete;
73 Scoped& operator=(const Scoped&) = delete;
74
75 private:
76 std::shared_ptr<ExclusiveAccess> shared;
77 typename MutexT::ScopedLock scopedLock;
78 T* const pointer;
79 };
80
81 private:
82 friend class ScopedLock;
83 MutexT mutex;
84 T item;
85 };
86
87 template<typename Traits>
88 class MutexBase {
89 public:
90 inline MutexBase();
91
92 inline ~MutexBase();
93
94 MutexBase(const MutexBase&) = delete;
95
96 MutexBase& operator=(const MutexBase&) = delete;
97
98 inline void Lock();
99
100 inline void Unlock();
101
102 inline void RdLock();
103
104 inline void RdUnlock();
105
106 class ScopedUnlock;
107 class ScopedLock;
108
109 class ScopedLock {
110 public:
111 inline explicit ScopedLock(const MutexBase& mutex);
112
113 inline explicit ScopedLock(const ScopedUnlock& scopedUnlock);
114
115 ScopedLock(const ScopedLock&) = delete;
116
117 ScopedLock& operator=(const ScopedLock&) = delete;
118
119 inline ~ScopedLock();
120
121 private:
122 template<typename>
123 friend class ConditionVariableBase;
124 friend class ScopedUnlock;
125 const MutexBase& mutex;
126 };
127
128 class ScopedReadLock {
129 public:
130 inline explicit ScopedReadLock(const MutexBase& mutex);
131
132 inline ~ScopedReadLock();
133
134 ScopedReadLock(const ScopedReadLock&) = delete;
135
136 ScopedReadLock& operator=(const ScopedReadLock&) = delete;
137
138 private:
139 template<typename>
140 friend class ConditionVariableBase;
141 const MutexBase& mutex;
142 };
143
144 using ScopedWriteLock = ScopedLock;
145
146 class ScopedUnlock {
147 public:
148 inline explicit ScopedUnlock(const ScopedLock& scopedLock);
149 inline ~ScopedUnlock();
150
151 ScopedUnlock(const ScopedUnlock&) = delete;
152 ScopedUnlock& operator=(const ScopedUnlock&) = delete;
153
154 private:
155 friend class ScopedLock;
156 const MutexBase& mutex;
157 };
158
159 private:
160 template<typename>
161 friend class ConditionVariableBase;
162 mutable typename Traits::MutexT mutex;
163 };
164
165 template<typename Traits>
166 class ConditionVariableBase {
167 public:
168 inline ConditionVariableBase();
169
170 inline ~ConditionVariableBase();
171
172 using ScopedLock = typename MutexBase<Traits>::ScopedLock;
173
174 ConditionVariableBase(const ConditionVariableBase&) = delete;
175 ConditionVariableBase& operator=(const ConditionVariableBase&) = delete;
176
177 inline void Broadcast(const ScopedLock&);
178
179 inline void Signal(const ScopedLock&);
180
181 inline void Wait(const ScopedLock& scopedLock);
182
183 private:
184 typename Traits::CondT cond;
185 };
186
187 struct LibuvMutexTraits {
188 using CondT = uv_cond_t;
189 using MutexT = uv_mutex_t;
190
CondInitLibuvMutexTraits191 static inline int CondInit(CondT* cond)
192 {
193 return uv_cond_init(cond);
194 }
195
MutexInitLibuvMutexTraits196 static inline int MutexInit(MutexT* mutex)
197 {
198 return uv_mutex_init(mutex);
199 }
200
CondBroadcastLibuvMutexTraits201 static inline void CondBroadcast(CondT* cond)
202 {
203 uv_cond_broadcast(cond);
204 }
205
CondDestroyLibuvMutexTraits206 static inline void CondDestroy(CondT* cond)
207 {
208 uv_cond_destroy(cond);
209 }
210
CondSignalLibuvMutexTraits211 static inline void CondSignal(CondT* cond)
212 {
213 uv_cond_signal(cond);
214 }
215
CondWaitLibuvMutexTraits216 static inline void CondWait(CondT* cond, MutexT* mutex)
217 {
218 uv_cond_wait(cond, mutex);
219 }
220
MutexDestroyLibuvMutexTraits221 static inline void MutexDestroy(MutexT* mutex)
222 {
223 uv_mutex_destroy(mutex);
224 }
225
MutexLockLibuvMutexTraits226 static inline void MutexLock(MutexT* mutex)
227 {
228 uv_mutex_lock(mutex);
229 }
230
MutexUnlockLibuvMutexTraits231 static inline void MutexUnlock(MutexT* mutex)
232 {
233 uv_mutex_unlock(mutex);
234 }
235
MutexRdlockLibuvMutexTraits236 static inline void MutexRdlock(MutexT* mutex)
237 {
238 uv_mutex_lock(mutex);
239 }
240
MutexRdunlockLibuvMutexTraits241 static inline void MutexRdunlock(MutexT* mutex)
242 {
243 uv_mutex_unlock(mutex);
244 }
245 };
246
247 struct LibuvRwlockTraits {
248 using MutexT = uv_rwlock_t;
249
MutexInitLibuvRwlockTraits250 static inline int MutexInit(MutexT* mutex)
251 {
252 return uv_rwlock_init(mutex);
253 }
254
MutexDestroyLibuvRwlockTraits255 static inline void MutexDestroy(MutexT* mutex)
256 {
257 uv_rwlock_destroy(mutex);
258 }
259
MutexLockLibuvRwlockTraits260 static inline void MutexLock(MutexT* mutex)
261 {
262 uv_rwlock_wrlock(mutex);
263 }
264
MutexUnlockLibuvRwlockTraits265 static inline void MutexUnlock(MutexT* mutex)
266 {
267 uv_rwlock_wrunlock(mutex);
268 }
269
MutexRdlockLibuvRwlockTraits270 static inline void MutexRdlock(MutexT* mutex)
271 {
272 uv_rwlock_rdlock(mutex);
273 }
274
MutexRdunlockLibuvRwlockTraits275 static inline void MutexRdunlock(MutexT* mutex)
276 {
277 uv_rwlock_rdunlock(mutex);
278 }
279 };
280
281 template<typename Traits>
ConditionVariableBase()282 ConditionVariableBase<Traits>::ConditionVariableBase()
283 {
284 CHECK_EQ(0, Traits::CondInit(&cond));
285 }
286
287 template<typename Traits>
~ConditionVariableBase()288 ConditionVariableBase<Traits>::~ConditionVariableBase()
289 {
290 Traits::CondDestroy(&cond);
291 }
292
293 template<typename Traits>
Broadcast(const ScopedLock &)294 void ConditionVariableBase<Traits>::Broadcast(const ScopedLock&)
295 {
296 Traits::CondBroadcast(&cond);
297 }
298
299 template<typename Traits>
Signal(const ScopedLock &)300 void ConditionVariableBase<Traits>::Signal(const ScopedLock&)
301 {
302 Traits::CondSignal(&cond);
303 }
304
305 template<typename Traits>
Wait(const ScopedLock & scopedLock)306 void ConditionVariableBase<Traits>::Wait(const ScopedLock& scopedLock)
307 {
308 Traits::CondWait(&cond, &scopedLock.mutex.mutex);
309 }
310
311 template<typename Traits>
MutexBase()312 MutexBase<Traits>::MutexBase()
313 {
314 CHECK_EQ(0, Traits::MutexInit(&mutex));
315 }
316
317 template<typename Traits>
~MutexBase()318 MutexBase<Traits>::~MutexBase()
319 {
320 Traits::MutexDestroy(&mutex);
321 }
322
323 template<typename Traits>
Lock()324 void MutexBase<Traits>::Lock()
325 {
326 Traits::MutexLock(&mutex);
327 }
328
329 template<typename Traits>
Unlock()330 void MutexBase<Traits>::Unlock()
331 {
332 Traits::MutexUnlock(&mutex);
333 }
334
335 template<typename Traits>
RdLock()336 void MutexBase<Traits>::RdLock()
337 {
338 Traits::MutexRdlock(&mutex);
339 }
340
341 template<typename Traits>
RdUnlock()342 void MutexBase<Traits>::RdUnlock()
343 {
344 Traits::MutexRdunlock(&mutex);
345 }
346
347 template<typename Traits>
ScopedLock(const MutexBase & mutex)348 MutexBase<Traits>::ScopedLock::ScopedLock(const MutexBase& mutex) : mutex(mutex)
349 {
350 Traits::MutexLock(&mutex.mutex);
351 }
352
353 template<typename Traits>
ScopedLock(const ScopedUnlock & scopedUnlock)354 MutexBase<Traits>::ScopedLock::ScopedLock(const ScopedUnlock& scopedUnlock) : MutexBase(scopedUnlock.mutex)
355 {}
356
357 template<typename Traits>
~ScopedLock()358 MutexBase<Traits>::ScopedLock::~ScopedLock()
359 {
360 Traits::MutexUnlock(&mutex.mutex);
361 }
362
363 template<typename Traits>
ScopedReadLock(const MutexBase & mutex)364 MutexBase<Traits>::ScopedReadLock::ScopedReadLock(const MutexBase& mutex) : mutex(mutex)
365 {
366 Traits::MutexRdlock(&mutex.mutex);
367 }
368
369 template<typename Traits>
~ScopedReadLock()370 MutexBase<Traits>::ScopedReadLock::~ScopedReadLock()
371 {
372 Traits::MutexRdunlock(&mutex.mutex);
373 }
374
375 template<typename Traits>
ScopedUnlock(const ScopedLock & scopedLock)376 MutexBase<Traits>::ScopedUnlock::ScopedUnlock(const ScopedLock& scopedLock) : mutex(scopedLock.mutex)
377 {
378 Traits::MutexUnlock(&mutex.mutex);
379 }
380
381 template<typename Traits>
~ScopedUnlock()382 MutexBase<Traits>::ScopedUnlock::~ScopedUnlock()
383 {
384 Traits::MutexLock(&mutex.mutex);
385 }
386
387 } // namespace jsvm
388
389 #endif // SRC_JSVM_MUTEX_H_
390