/*
* 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 META_API_THREADING_MUTEX_H
#define META_API_THREADING_MUTEX_H
#include
#include "primitive_api.h"
CORE_BEGIN_NAMESPACE()
/**
* @brief Mutex class that can be used across shared library boundaries and in public headers.
* It is not copyable or movable.
*/
class Mutex {
public:
META_NO_COPY_MOVE(Mutex)
/**
* @brief Construct mutex using sync api.
*/
Mutex() : api_(GetSyncApi().mutex)
{
api_.create(MutexType::NORMAL, handle_);
}
/**
* @brief Destroy mutex.
*/
~Mutex()
{
api_.destroy(handle_);
}
/**
* @brief Lock mutex, call it again for already locked mutex has undefined behaviour.
*/
void Lock()
{
api_.lock(handle_);
}
/**
* @brief Unlock mutex, calling it for not locked mutex has undefined behaviour.
*/
void Unlock()
{
api_.unlock(handle_);
}
private:
SyncApi::MutexApi api_;
MutexHandle handle_;
};
/**
* @brief General-purpose mutex ownership wrapper, allows to transfer ownership by moving.
*/
template
class UniqueLock {
public:
META_NO_COPY(UniqueLock)
/**
* @brief Construct lock from mutex and lock it.
*/
explicit UniqueLock(Mutex& mutex) : mutex_(&mutex)
{
Lock();
}
/**
* @brief Construct by moving from another lock.
*/
UniqueLock(UniqueLock&& lock) : locked_(lock.locked_), mutex_(lock.mutex_)
{
lock.mutex_ = nullptr;
lock.locked_ = false;
}
/**
* @brief Destroy lock, unlocks associated mutex if it is locked.
*/
~UniqueLock()
{
if (mutex_ && locked_) {
mutex_->Unlock();
}
}
/**
* @brief Move from another lock, unlock the previously associated mutex if locked.
*/
UniqueLock& operator=(UniqueLock&& lock)
{
if (&lock == this) {
return *this;
}
if (mutex_ && locked_) {
mutex_->Unlock();
}
locked_ = lock.locked_;
mutex_ = lock.mutex_;
lock.mutex_ = nullptr;
lock.locked_ = false;
return *this;
}
/**
* @brief Lock the mutex, must have associated mutex which is not locked.
*/
void Lock()
{
CORE_ASSERT_MSG(mutex_ && !locked_, "trying to lock mutex in invalid state");
mutex_->Lock();
locked_ = true;
}
/**
* @brief Unlock the mutex, must have associated mutex which is locked.
*/
void Unlock()
{
CORE_ASSERT_MSG(mutex_ && locked_, "trying to unlock mutex in invalid state");
mutex_->Unlock();
locked_ = false;
}
/**
* @brief Returns true if this lock has associated mutex that is locked with this lock.
*/
explicit operator bool() const
{
return mutex_ && locked_;
}
private:
bool locked_ {};
Mutex* mutex_;
};
CORE_END_NAMESPACE()
#endif