• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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