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 21namespace panda::ecmascript { 22 23Mutex::Mutex(bool is_init) : mutex_() 24{ 25 if (is_init) { 26 Init(nullptr); 27 } 28} 29 30Mutex::~Mutex() 31{ 32 [[maybe_unused]]int rc = pthread_mutex_destroy(&mutex_); 33 FATAL_IF_ERROR("pthread_mutex_destroy", rc); 34} 35 36void 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 42void Mutex::Lock() 43{ 44 [[maybe_unused]]int rc = pthread_mutex_lock(&mutex_); 45 FATAL_IF_ERROR("pthread_mutex_lock", rc); 46} 47 48bool 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 60void Mutex::Unlock() 61{ 62 [[maybe_unused]]int rc = pthread_mutex_unlock(&mutex_); 63 FATAL_IF_ERROR("pthread_mutex_unlock", rc); 64} 65 66RecursiveMutex::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 74RWLock::RWLock() : rwlock_() 75{ 76 [[maybe_unused]]int rc = pthread_rwlock_init(&rwlock_, nullptr); 77 FATAL_IF_ERROR("pthread_rwlock_init", rc); 78} 79 80RWLock::~RWLock() 81{ 82 [[maybe_unused]]int rc = pthread_rwlock_destroy(&rwlock_); 83 FATAL_IF_ERROR("pthread_rwlock_destroy", rc); 84} 85 86void RWLock::ReadLock() 87{ 88 [[maybe_unused]]int rc = pthread_rwlock_rdlock(&rwlock_); 89 FATAL_IF_ERROR("pthread_rwlock_rdlock", rc); 90} 91 92void RWLock::WriteLock() 93{ 94 [[maybe_unused]]int rc = pthread_rwlock_wrlock(&rwlock_); 95 FATAL_IF_ERROR("pthread_rwlock_wrlock", rc); 96} 97 98bool 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 110bool 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 122void RWLock::Unlock() 123{ 124 [[maybe_unused]]int rc = pthread_rwlock_unlock(&rwlock_); 125 FATAL_IF_ERROR("pthread_rwlock_unlock", rc); 126} 127 128ConditionVariable::ConditionVariable() : cond_() 129{ 130 [[maybe_unused]]int rc = pthread_cond_init(&cond_, nullptr); 131 FATAL_IF_ERROR("pthread_cond_init", rc); 132} 133 134ConditionVariable::~ConditionVariable() 135{ 136 [[maybe_unused]]int rc = pthread_cond_destroy(&cond_); 137 FATAL_IF_ERROR("pthread_cond_destroy", rc); 138} 139 140void ConditionVariable::Signal() 141{ 142 [[maybe_unused]]int rc = pthread_cond_signal(&cond_); 143 FATAL_IF_ERROR("pthread_cond_signal", rc); 144} 145 146void ConditionVariable::SignalAll() 147{ 148 [[maybe_unused]]int rc = pthread_cond_broadcast(&cond_); 149 FATAL_IF_ERROR("pthread_cond_broadcast", rc); 150} 151 152void 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 158struct 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 178bool 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