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 META_API_THREADING_MUTEX_H
17 #define META_API_THREADING_MUTEX_H
18 
19 #include <meta/base/interface_macros.h>
20 
21 #include "primitive_api.h"
22 
CORE_BEGIN_NAMESPACE()23 CORE_BEGIN_NAMESPACE()
24 
25 /**
26  * @brief Mutex class that can be used across shared library boundaries and in public headers.
27  *        It is not copyable or movable.
28  */
29 class Mutex {
30 public:
31     META_NO_COPY_MOVE(Mutex)
32 
33     /**
34      * @brief Construct mutex using sync api.
35      */
36     Mutex() : api_(GetSyncApi().mutex)
37     {
38         api_.create(MutexType::NORMAL, handle_);
39     }
40 
41     /**
42      * @brief Destroy mutex.
43      */
44     ~Mutex()
45     {
46         api_.destroy(handle_);
47     }
48 
49     /**
50      * @brief Lock mutex, call it again for already locked mutex has undefined behaviour.
51      */
52     void Lock()
53     {
54         api_.lock(handle_);
55     }
56 
57     /**
58      * @brief Unlock mutex, calling it for not locked mutex has undefined behaviour.
59      */
60     void Unlock()
61     {
62         api_.unlock(handle_);
63     }
64 
65 private:
66     SyncApi::MutexApi api_;
67     MutexHandle handle_;
68 };
69 
70 /**
71  * @brief General-purpose mutex ownership wrapper, allows to transfer ownership by moving.
72  */
73 template<class Mutex>
74 class UniqueLock {
75 public:
META_NO_COPY(UniqueLock)76     META_NO_COPY(UniqueLock)
77     /**
78      * @brief Construct lock from mutex and lock it.
79      */
80     explicit UniqueLock(Mutex& mutex) : mutex_(&mutex)
81     {
82         Lock();
83     }
84 
85     /**
86      * @brief Construct by moving from another lock.
87      */
UniqueLock(UniqueLock && lock)88     UniqueLock(UniqueLock&& lock) : locked_(lock.locked_), mutex_(lock.mutex_)
89     {
90         lock.mutex_ = nullptr;
91         lock.locked_ = false;
92     }
93 
94     /**
95      * @brief Destroy lock, unlocks associated mutex if it is locked.
96      */
~UniqueLock()97     ~UniqueLock()
98     {
99         if (mutex_ && locked_) {
100             mutex_->Unlock();
101         }
102     }
103 
104     /**
105      * @brief Move from another lock, unlock the previously associated mutex if locked.
106      */
107     UniqueLock& operator=(UniqueLock&& lock)
108     {
109         if (&lock == this) {
110             return *this;
111         }
112         if (mutex_ && locked_) {
113             mutex_->Unlock();
114         }
115         locked_ = lock.locked_;
116         mutex_ = lock.mutex_;
117         lock.mutex_ = nullptr;
118         lock.locked_ = false;
119         return *this;
120     }
121 
122     /**
123      * @brief Lock the mutex, must have associated mutex which is not locked.
124      */
Lock()125     void Lock()
126     {
127         CORE_ASSERT_MSG(mutex_ && !locked_, "trying to lock mutex in invalid state");
128         mutex_->Lock();
129         locked_ = true;
130     }
131 
132     /**
133      * @brief Unlock the mutex, must have associated mutex which is locked.
134      */
Unlock()135     void Unlock()
136     {
137         CORE_ASSERT_MSG(mutex_ && locked_, "trying to unlock mutex in invalid state");
138         mutex_->Unlock();
139         locked_ = false;
140     }
141 
142     /**
143      * @brief Returns true if this lock has associated mutex that is locked with this lock.
144      */
145     explicit operator bool() const
146     {
147         return mutex_ && locked_;
148     }
149 
150 private:
151     bool locked_ {};
152     Mutex* mutex_;
153 };
154 
155 CORE_END_NAMESPACE()
156 
157 #endif
158