/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SRC_JSVM_MUTEX_H_ #define SRC_JSVM_MUTEX_H_ #include // std::shared_ptr #include // std::forward #include "jsvm_util.h" #include "uv.h" namespace jsvm { template class ConditionVariableBase; template class MutexBase; struct LibuvMutexTraits; struct LibuvRwlockTraits; using ConditionVariable = ConditionVariableBase; using Mutex = MutexBase; using RwLock = MutexBase; template class ExclusiveAccess { public: ExclusiveAccess() = default; template explicit ExclusiveAccess(Args&&... args) : item(std::forward(args)...) {} ExclusiveAccess(const ExclusiveAccess&) = delete; ExclusiveAccess& operator=(const ExclusiveAccess&) = delete; class Scoped { public: // ExclusiveAccess will commonly be used in conjunction with std::shared_ptr // and without this constructor it's too easy to forget to keep a reference // around to the shared_ptr while operating on the ExclusiveAccess object. explicit Scoped(const std::shared_ptr& shared) : shared(shared), scopedLock(shared->mutex), pointer(&shared->item) {} explicit Scoped(ExclusiveAccess* exclusiveAccess) : shared(), scopedLock(exclusiveAccess->mutex), pointer(&exclusiveAccess->item) {} T& operator*() const { return *pointer; } T* operator->() const { return pointer; } Scoped(const Scoped&) = delete; Scoped& operator=(const Scoped&) = delete; private: std::shared_ptr shared; typename MutexT::ScopedLock scopedLock; T* const pointer; }; private: friend class ScopedLock; MutexT mutex; T item; }; template class MutexBase { public: inline MutexBase(); inline ~MutexBase(); MutexBase(const MutexBase&) = delete; MutexBase& operator=(const MutexBase&) = delete; inline void Lock(); inline void Unlock(); inline void RdLock(); inline void RdUnlock(); class ScopedUnlock; class ScopedLock; class ScopedLock { public: inline explicit ScopedLock(const MutexBase& mutex); inline explicit ScopedLock(const ScopedUnlock& scopedUnlock); ScopedLock(const ScopedLock&) = delete; ScopedLock& operator=(const ScopedLock&) = delete; inline ~ScopedLock(); private: template friend class ConditionVariableBase; friend class ScopedUnlock; const MutexBase& mutex; }; class ScopedReadLock { public: inline explicit ScopedReadLock(const MutexBase& mutex); inline ~ScopedReadLock(); ScopedReadLock(const ScopedReadLock&) = delete; ScopedReadLock& operator=(const ScopedReadLock&) = delete; private: template friend class ConditionVariableBase; const MutexBase& mutex; }; using ScopedWriteLock = ScopedLock; class ScopedUnlock { public: inline explicit ScopedUnlock(const ScopedLock& scopedLock); inline ~ScopedUnlock(); ScopedUnlock(const ScopedUnlock&) = delete; ScopedUnlock& operator=(const ScopedUnlock&) = delete; private: friend class ScopedLock; const MutexBase& mutex; }; private: template friend class ConditionVariableBase; mutable typename Traits::MutexT mutex; }; template class ConditionVariableBase { public: inline ConditionVariableBase(); inline ~ConditionVariableBase(); using ScopedLock = typename MutexBase::ScopedLock; ConditionVariableBase(const ConditionVariableBase&) = delete; ConditionVariableBase& operator=(const ConditionVariableBase&) = delete; inline void Broadcast(const ScopedLock&); inline void Signal(const ScopedLock&); inline void Wait(const ScopedLock& scopedLock); private: typename Traits::CondT cond; }; struct LibuvMutexTraits { using CondT = uv_cond_t; using MutexT = uv_mutex_t; static inline int CondInit(CondT* cond) { return uv_cond_init(cond); } static inline int MutexInit(MutexT* mutex) { return uv_mutex_init(mutex); } static inline void CondBroadcast(CondT* cond) { uv_cond_broadcast(cond); } static inline void CondDestroy(CondT* cond) { uv_cond_destroy(cond); } static inline void CondSignal(CondT* cond) { uv_cond_signal(cond); } static inline void CondWait(CondT* cond, MutexT* mutex) { uv_cond_wait(cond, mutex); } static inline void MutexDestroy(MutexT* mutex) { uv_mutex_destroy(mutex); } static inline void MutexLock(MutexT* mutex) { uv_mutex_lock(mutex); } static inline void MutexUnlock(MutexT* mutex) { uv_mutex_unlock(mutex); } static inline void MutexRdlock(MutexT* mutex) { uv_mutex_lock(mutex); } static inline void MutexRdunlock(MutexT* mutex) { uv_mutex_unlock(mutex); } }; struct LibuvRwlockTraits { using MutexT = uv_rwlock_t; static inline int MutexInit(MutexT* mutex) { return uv_rwlock_init(mutex); } static inline void MutexDestroy(MutexT* mutex) { uv_rwlock_destroy(mutex); } static inline void MutexLock(MutexT* mutex) { uv_rwlock_wrlock(mutex); } static inline void MutexUnlock(MutexT* mutex) { uv_rwlock_wrunlock(mutex); } static inline void MutexRdlock(MutexT* mutex) { uv_rwlock_rdlock(mutex); } static inline void MutexRdunlock(MutexT* mutex) { uv_rwlock_rdunlock(mutex); } }; template ConditionVariableBase::ConditionVariableBase() { CHECK_EQ(0, Traits::CondInit(&cond)); } template ConditionVariableBase::~ConditionVariableBase() { Traits::CondDestroy(&cond); } template void ConditionVariableBase::Broadcast(const ScopedLock&) { Traits::CondBroadcast(&cond); } template void ConditionVariableBase::Signal(const ScopedLock&) { Traits::CondSignal(&cond); } template void ConditionVariableBase::Wait(const ScopedLock& scopedLock) { Traits::CondWait(&cond, &scopedLock.mutex.mutex); } template MutexBase::MutexBase() { CHECK_EQ(0, Traits::MutexInit(&mutex)); } template MutexBase::~MutexBase() { Traits::MutexDestroy(&mutex); } template void MutexBase::Lock() { Traits::MutexLock(&mutex); } template void MutexBase::Unlock() { Traits::MutexUnlock(&mutex); } template void MutexBase::RdLock() { Traits::MutexRdlock(&mutex); } template void MutexBase::RdUnlock() { Traits::MutexRdunlock(&mutex); } template MutexBase::ScopedLock::ScopedLock(const MutexBase& mutex) : mutex(mutex) { Traits::MutexLock(&mutex.mutex); } template MutexBase::ScopedLock::ScopedLock(const ScopedUnlock& scopedUnlock) : MutexBase(scopedUnlock.mutex) {} template MutexBase::ScopedLock::~ScopedLock() { Traits::MutexUnlock(&mutex.mutex); } template MutexBase::ScopedReadLock::ScopedReadLock(const MutexBase& mutex) : mutex(mutex) { Traits::MutexRdlock(&mutex.mutex); } template MutexBase::ScopedReadLock::~ScopedReadLock() { Traits::MutexRdunlock(&mutex.mutex); } template MutexBase::ScopedUnlock::ScopedUnlock(const ScopedLock& scopedLock) : mutex(scopedLock.mutex) { Traits::MutexUnlock(&mutex.mutex); } template MutexBase::ScopedUnlock::~ScopedUnlock() { Traits::MutexLock(&mutex.mutex); } } // namespace jsvm #endif // SRC_JSVM_MUTEX_H_