• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 LIBPANDABASE_OS_MUTEX_H
17 #define LIBPANDABASE_OS_MUTEX_H
18 
19 #if defined(PANDA_USE_FUTEX)
20 #include "platforms/unix/libpandabase/futex/mutex.h"
21 #elif !defined(PANDA_TARGET_UNIX) && !defined(PANDA_TARGET_WINDOWS)
22 #error "Unsupported platform"
23 #endif
24 
25 #include "clang.h"
26 #include "macros.h"
27 
28 #include <atomic>
29 #include <pthread.h>
30 
31 namespace panda::os::memory {
32 
33 // Dummy lock which locks nothing
34 // but has the same methods as RWLock and Mutex.
35 // Can be used in Locks Holders.
36 class DummyLock {
37 public:
Lock()38     void Lock() const {}
Unlock()39     void Unlock() const {}
ReadLock()40     void ReadLock() const {}
WriteLock()41     void WriteLock() const {}
42 };
43 
44 #if defined(PANDA_USE_FUTEX)
45 using Mutex = panda::os::unix::memory::futex::Mutex;
46 using RecursiveMutex = panda::os::unix::memory::futex::RecursiveMutex;
47 using RWLock = panda::os::unix::memory::futex::RWLock;
48 using ConditionVariable = panda::os::unix::memory::futex::ConditionVariable;
49 #else
50 class ConditionVariable;
51 
52 class CAPABILITY("mutex") Mutex {
53 public:
54     explicit Mutex(bool is_init = true);
55 
56     ~Mutex();
57 
58     void Lock() ACQUIRE();
59 
60     bool TryLock() TRY_ACQUIRE(true);
61 
62     void Unlock() RELEASE();
63 
64     // TODO: Extract common part as an interface.
DoNotCheckOnDeadlock()65     static bool DoNotCheckOnDeadlock()
66     {
67         return no_check_for_deadlock_;
68     }
69 
IgnoreChecksOnDeadlock()70     static void IgnoreChecksOnDeadlock()
71     {
72         no_check_for_deadlock_ = true;
73     }
74 
75 protected:
76     void Init(pthread_mutexattr_t *attrs);
77 
78 private:
79     pthread_mutex_t mutex_;
80 
81     // This field is set to false in case of deadlock with daemon threads (only daemon threads
82     // are not finished and they have state IS_BLOCKED). In this case we should terminate
83     // those threads ignoring failures on lock structures destructors.
84     static std::atomic_bool no_check_for_deadlock_;
85 
86     NO_COPY_SEMANTIC(Mutex);
87     NO_MOVE_SEMANTIC(Mutex);
88 
89     friend ConditionVariable;
90 };
91 
92 class CAPABILITY("mutex") RecursiveMutex : public Mutex {
93 public:
94     RecursiveMutex();
95 
96     ~RecursiveMutex() = default;
97 
98     NO_COPY_SEMANTIC(RecursiveMutex);
99     NO_MOVE_SEMANTIC(RecursiveMutex);
100 };
101 
102 class CAPABILITY("mutex") RWLock {
103 public:
104     RWLock();
105 
106     ~RWLock();
107 
108     void ReadLock() ACQUIRE_SHARED();
109 
110     void WriteLock() ACQUIRE();
111 
112     bool TryReadLock() TRY_ACQUIRE_SHARED(true);
113 
114     bool TryWriteLock() TRY_ACQUIRE(true);
115 
116     void Unlock() RELEASE_GENERIC();
117 
118 private:
119     pthread_rwlock_t rwlock_;
120 
121     NO_COPY_SEMANTIC(RWLock);
122     NO_MOVE_SEMANTIC(RWLock);
123 };
124 
125 // Some RTOS could not have support for condition variables, so this primitive should be used carefully
126 class ConditionVariable {
127 public:
128     ConditionVariable();
129 
130     ~ConditionVariable();
131 
132     void Signal();
133 
134     void SignalAll();
135 
136     void Wait(Mutex *mutex);
137 
138     bool TimedWait(Mutex *mutex, uint64_t ms, uint64_t ns = 0, bool is_absolute = false);
139 
140 private:
141     pthread_cond_t cond_;
142 
143     NO_COPY_SEMANTIC(ConditionVariable);
144     NO_MOVE_SEMANTIC(ConditionVariable);
145 };
146 #endif  // PANDA_USE_FUTEX
147 
148 using PandaThreadKey = pthread_key_t;
149 const auto PandaGetspecific = pthread_getspecific;     // NOLINT(readability-identifier-naming)
150 const auto PandaSetspecific = pthread_setspecific;     // NOLINT(readability-identifier-naming)
151 const auto PandaThreadKeyCreate = pthread_key_create;  // NOLINT(readability-identifier-naming)
152 
153 template <class T, bool need_lock = true>
154 class SCOPED_CAPABILITY LockHolder {
155 public:
LockHolder(T & lock)156     explicit LockHolder(T &lock) ACQUIRE(lock) : lock_(lock)
157     {
158         if constexpr (need_lock) {  // NOLINTNEXTLINE(readability-braces-around-statements)
159             lock_.Lock();
160         }
161     }
162 
RELEASE()163     ~LockHolder() RELEASE()
164     {
165         if constexpr (need_lock) {  // NOLINTNEXTLINE(readability-braces-around-statements)
166             lock_.Unlock();
167         }
168     }
169 
170 private:
171     T &lock_;
172 
173     NO_COPY_SEMANTIC(LockHolder);
174     NO_MOVE_SEMANTIC(LockHolder);
175 };
176 
177 template <class T, bool need_lock = true>
178 class SCOPED_CAPABILITY ReadLockHolder {
179 public:
ReadLockHolder(T & lock)180     explicit ReadLockHolder(T &lock) ACQUIRE_SHARED(lock) : lock_(lock)
181     {
182         if constexpr (need_lock) {  // NOLINTNEXTLINE(readability-braces-around-statements)
183             lock_.ReadLock();
184         }
185     }
186 
RELEASE()187     ~ReadLockHolder() RELEASE()
188     {
189         if constexpr (need_lock) {  // NOLINTNEXTLINE(readability-braces-around-statements)
190             lock_.Unlock();
191         }
192     }
193 
194 private:
195     T &lock_;
196 
197     NO_COPY_SEMANTIC(ReadLockHolder);
198     NO_MOVE_SEMANTIC(ReadLockHolder);
199 };
200 
201 template <class T, bool need_lock = true>
202 class SCOPED_CAPABILITY WriteLockHolder {
203 public:
WriteLockHolder(T & lock)204     explicit WriteLockHolder(T &lock) ACQUIRE(lock) : lock_(lock)
205     {
206         if constexpr (need_lock) {  // NOLINTNEXTLINE(readability-braces-around-statements)
207             lock_.WriteLock();
208         }
209     }
210 
RELEASE()211     ~WriteLockHolder() RELEASE()
212     {
213         if constexpr (need_lock) {  // NOLINTNEXTLINE(readability-braces-around-statements)
214             lock_.Unlock();
215         }
216     }
217 
218 private:
219     T &lock_;
220 
221     NO_COPY_SEMANTIC(WriteLockHolder);
222     NO_MOVE_SEMANTIC(WriteLockHolder);
223 };
224 
225 }  // namespace panda::os::memory
226 
227 #endif  // LIBPANDABASE_OS_MUTEX_H
228