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