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