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