• 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 #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