/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/platform/mutex.h" #include "ecmascript/log_wrapper.h" #include <cstring> #include <ctime> namespace panda::ecmascript { inline void FatalIfError(const char *f, int rc) { if (rc != 0) { LOG_ECMA(FATAL)<< f << " failed: " << rc; } } Mutex::Mutex(bool is_init) : mutex_() { if (is_init) { Init(nullptr); } } Mutex::~Mutex() { int rc = pthread_mutex_destroy(&mutex_); FatalIfError("pthread_mutex_destroy", rc); } void Mutex::Init(pthread_mutexattr_t *attrs) { int rc = pthread_mutex_init(&mutex_, attrs); FatalIfError("pthread_mutex_init", rc); } void Mutex::Lock() { int rc = pthread_mutex_lock(&mutex_); FatalIfError("pthread_mutex_lock", rc); } bool Mutex::TryLock() { int rc = pthread_mutex_trylock(&mutex_); if (rc == EBUSY) { return false; } FatalIfError("pthread_mutex_trylock", rc); return true; } void Mutex::Unlock() { int rc = pthread_mutex_unlock(&mutex_); FatalIfError("pthread_mutex_unlock", rc); } RecursiveMutex::RecursiveMutex() : Mutex(false) { pthread_mutexattr_t attrs; pthread_mutexattr_init(&attrs); pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE); Init(&attrs); } RWLock::RWLock() : rwlock_() { int rc = pthread_rwlock_init(&rwlock_, nullptr); FatalIfError("pthread_rwlock_init", rc); } RWLock::~RWLock() { int rc = pthread_rwlock_destroy(&rwlock_); FatalIfError("pthread_rwlock_destroy", rc); } void RWLock::ReadLock() { int rc = pthread_rwlock_rdlock(&rwlock_); FatalIfError("pthread_rwlock_rdlock", rc); } void RWLock::WriteLock() { int rc = pthread_rwlock_wrlock(&rwlock_); FatalIfError("pthread_rwlock_wrlock", rc); } bool RWLock::TryReadLock() { int rc = pthread_rwlock_tryrdlock(&rwlock_); if (rc == EBUSY) { return false; } FatalIfError("pthread_rwlock_tryrdlock", rc); return true; } bool RWLock::TryWriteLock() { int rc = pthread_rwlock_trywrlock(&rwlock_); if (rc == EBUSY) { return false; } FatalIfError("pthread_rwlock_trywrlock", rc); return true; } void RWLock::Unlock() { int rc = pthread_rwlock_unlock(&rwlock_); FatalIfError("pthread_rwlock_unlock", rc); } ConditionVariable::ConditionVariable() : cond_() { int rc = pthread_cond_init(&cond_, nullptr); FatalIfError("pthread_cond_init", rc); } ConditionVariable::~ConditionVariable() { int rc = pthread_cond_destroy(&cond_); FatalIfError("pthread_cond_destroy", rc); } void ConditionVariable::Signal() { int rc = pthread_cond_signal(&cond_); FatalIfError("pthread_cond_signal", rc); } void ConditionVariable::SignalAll() { int rc = pthread_cond_broadcast(&cond_); FatalIfError("pthread_cond_broadcast", rc); } void ConditionVariable::Wait(Mutex *mutex) { int rc = pthread_cond_wait(&cond_, &mutex->mutex_); FatalIfError("pthread_cond_wait", rc); } struct timespec ConvertTime(uint64_t ms, uint64_t ns, bool is_absolute) { struct timespec abs_time = {0, 0}; if (!is_absolute) { clock_gettime(CLOCK_REALTIME, &abs_time); } const int64_t MILLISECONDS_PER_SEC = 1000; const int64_t NANOSECONDS_PER_MILLISEC = 1000000; const int64_t NANOSECONDS_PER_SEC = 1000000000; time_t seconds = ms / MILLISECONDS_PER_SEC; time_t nanoseconds = (ms % MILLISECONDS_PER_SEC) * NANOSECONDS_PER_MILLISEC + ns; abs_time.tv_sec += seconds; abs_time.tv_nsec += nanoseconds; if (abs_time.tv_nsec >= NANOSECONDS_PER_SEC) { abs_time.tv_nsec -= NANOSECONDS_PER_SEC; abs_time.tv_sec++; } return abs_time; } bool ConditionVariable::TimedWait(Mutex *mutex, uint64_t ms, uint64_t ns, bool is_absolute) { struct timespec abs_time = ConvertTime(ms, ns, is_absolute); int rc = pthread_cond_timedwait(&cond_, &mutex->mutex_, &abs_time); if (rc != 0) { if (rc == ETIMEDOUT) { // interrupted return true; } } FatalIfError("pthread_cond_timedwait", rc); return false; } } // namespace panda::ecmascript