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 #include "mutex.h"
17
18 #include "utils/logger.h"
19
20 #include <cstring>
21
22 #include <ctime>
23
24 namespace panda::os::memory {
25
26 std::atomic_bool Mutex::no_check_for_deadlock_ = false;
27
FatalIfError(const char * f,int rc)28 ALWAYS_INLINE inline void FatalIfError(const char *f, int rc)
29 {
30 if (rc != 0) {
31 #ifndef PANDA_TARGET_MOBILE
32 if (!Mutex::DoNotCheckOnDeadlock()) {
33 #endif // PANDA_TARGET_MOBILE
34 LOG(FATAL, COMMON) << f << " failed: " << Error(rc).ToString();
35 #ifndef PANDA_TARGET_MOBILE
36 } else {
37 LOG(WARNING, COMMON) << f << " failed: deadlock detected";
38 }
39 #endif // PANDA_TARGET_MOBILE
40 }
41 }
42
Mutex(bool is_init)43 Mutex::Mutex(bool is_init) : mutex_()
44 {
45 if (is_init) {
46 Init(nullptr);
47 }
48 }
49
~Mutex()50 Mutex::~Mutex()
51 {
52 int rc = pthread_mutex_destroy(&mutex_);
53 FatalIfError("pthread_mutex_destroy", rc);
54 }
55
Init(pthread_mutexattr_t * attrs)56 void Mutex::Init(pthread_mutexattr_t *attrs)
57 {
58 int rc = pthread_mutex_init(&mutex_, attrs);
59 FatalIfError("pthread_mutex_init", rc);
60 }
61
Lock()62 void Mutex::Lock()
63 {
64 int rc = pthread_mutex_lock(&mutex_);
65 FatalIfError("pthread_mutex_lock", rc);
66 }
67
TryLock()68 bool Mutex::TryLock()
69 {
70 int rc = pthread_mutex_trylock(&mutex_);
71 if (rc == EBUSY) {
72 return false;
73 }
74
75 FatalIfError("pthread_mutex_trylock", rc);
76
77 return true;
78 }
79
Unlock()80 void Mutex::Unlock()
81 {
82 int rc = pthread_mutex_unlock(&mutex_);
83 FatalIfError("pthread_mutex_unlock", rc);
84 }
85
RecursiveMutex()86 RecursiveMutex::RecursiveMutex() : Mutex(false)
87 {
88 pthread_mutexattr_t attrs;
89 pthread_mutexattr_init(&attrs);
90 pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
91 Init(&attrs);
92 }
93
RWLock()94 RWLock::RWLock() : rwlock_()
95 {
96 int rc = pthread_rwlock_init(&rwlock_, nullptr);
97 FatalIfError("pthread_rwlock_init", rc);
98 }
99
~RWLock()100 RWLock::~RWLock()
101 {
102 int rc = pthread_rwlock_destroy(&rwlock_);
103 FatalIfError("pthread_rwlock_destroy", rc);
104 }
105
ReadLock()106 void RWLock::ReadLock()
107 {
108 int rc = pthread_rwlock_rdlock(&rwlock_);
109 FatalIfError("pthread_rwlock_rdlock", rc);
110 }
111
WriteLock()112 void RWLock::WriteLock()
113 {
114 int rc = pthread_rwlock_wrlock(&rwlock_);
115 FatalIfError("pthread_rwlock_wrlock", rc);
116 }
117
TryReadLock()118 bool RWLock::TryReadLock()
119 {
120 int rc = pthread_rwlock_tryrdlock(&rwlock_);
121 if (rc == EBUSY) {
122 return false;
123 }
124
125 FatalIfError("pthread_rwlock_tryrdlock", rc);
126
127 return true;
128 }
129
TryWriteLock()130 bool RWLock::TryWriteLock()
131 {
132 int rc = pthread_rwlock_trywrlock(&rwlock_);
133 if (rc == EBUSY) {
134 return false;
135 }
136
137 FatalIfError("pthread_rwlock_trywrlock", rc);
138
139 return true;
140 }
141
Unlock()142 void RWLock::Unlock()
143 {
144 int rc = pthread_rwlock_unlock(&rwlock_);
145 FatalIfError("pthread_rwlock_unlock", rc);
146 }
147
ConditionVariable()148 ConditionVariable::ConditionVariable() : cond_()
149 {
150 int rc = pthread_cond_init(&cond_, nullptr);
151 FatalIfError("pthread_cond_init", rc);
152 }
153
~ConditionVariable()154 ConditionVariable::~ConditionVariable()
155 {
156 int rc = pthread_cond_destroy(&cond_);
157 FatalIfError("pthread_cond_destroy", rc);
158 }
159
Signal()160 void ConditionVariable::Signal()
161 {
162 int rc = pthread_cond_signal(&cond_);
163 FatalIfError("pthread_cond_signal", rc);
164 }
165
SignalAll()166 void ConditionVariable::SignalAll()
167 {
168 int rc = pthread_cond_broadcast(&cond_);
169 FatalIfError("pthread_cond_broadcast", rc);
170 }
171
Wait(Mutex * mutex)172 void ConditionVariable::Wait(Mutex *mutex)
173 {
174 int rc = pthread_cond_wait(&cond_, &mutex->mutex_);
175 FatalIfError("pthread_cond_wait", rc);
176 }
177
ConvertTime(uint64_t ms,uint64_t ns,bool is_absolute)178 struct timespec ConvertTime(uint64_t ms, uint64_t ns, bool is_absolute)
179 {
180 struct timespec abs_time = {0, 0};
181 if (!is_absolute) {
182 clock_gettime(CLOCK_REALTIME, &abs_time);
183 }
184 const int64_t MILLISECONDS_PER_SEC = 1000;
185 const int64_t NANOSECONDS_PER_MILLISEC = 1000000;
186 const int64_t NANOSECONDS_PER_SEC = 1000000000;
187 time_t seconds = ms / MILLISECONDS_PER_SEC;
188 time_t nanoseconds = (ms % MILLISECONDS_PER_SEC) * NANOSECONDS_PER_MILLISEC + ns;
189 abs_time.tv_sec += seconds;
190 abs_time.tv_nsec += nanoseconds;
191 if (abs_time.tv_nsec >= NANOSECONDS_PER_SEC) {
192 abs_time.tv_nsec -= NANOSECONDS_PER_SEC;
193 abs_time.tv_sec++;
194 }
195 return abs_time;
196 }
197
TimedWait(Mutex * mutex,uint64_t ms,uint64_t ns,bool is_absolute)198 bool ConditionVariable::TimedWait(Mutex *mutex, uint64_t ms, uint64_t ns, bool is_absolute /* = false */)
199 {
200 struct timespec abs_time = ConvertTime(ms, ns, is_absolute);
201 int rc = pthread_cond_timedwait(&cond_, &mutex->mutex_, &abs_time);
202 if (rc != 0) {
203 if (rc == ETIMEDOUT) {
204 // interrupted
205 return true;
206 }
207 }
208 FatalIfError("pthread_cond_timedwait", rc);
209 return false;
210 }
211
212 } // namespace panda::os::memory
213