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