/* * Copyright (c) 2021-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. */ #define HST_LOG_TAG "ConditionVariable" #include "osal/task/condition_variable.h" #include #include #include "common/log.h" namespace { constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "ConditionVariable" }; } namespace { inline long long TmToNs(struct timespec tm) { return tm.tv_sec * std::giga::num + tm.tv_nsec; } inline struct timespec NsToTm(long long ns) { return {ns / std::giga::num, static_cast(ns % std::giga::num)}; } } namespace OHOS { namespace Media { ConditionVariable::ConditionVariable() noexcept : condInited_(true) { pthread_condattr_t attr; pthread_condattr_init(&attr); #ifndef __LITEOS_M__ #ifdef USING_CLOCK_REALTIME pthread_condattr_setclock(&attr, CLOCK_REALTIME); #else pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); #endif #endif int rtv = pthread_cond_init(&cond_, &attr); if (rtv != 0) { condInited_ = false; MEDIA_LOG_E("failed to init pthread cond variable"); } pthread_condattr_destroy(&attr); } ConditionVariable::~ConditionVariable() noexcept { if (condInited_) { pthread_cond_destroy(&cond_); } } void ConditionVariable::NotifyOne() noexcept { FALSE_RETURN_MSG(condInited_, "NotifyOne uninitialized pthread cond"); int ret = pthread_cond_signal(&cond_); FALSE_LOG_MSG(ret == 0, "NotifyOne failed with errno = " PUBLIC_LOG_D32, ret); } void ConditionVariable::NotifyAll() noexcept { FALSE_RETURN_MSG(condInited_, "NotifyAll uninitialized pthread cond"); int ret = pthread_cond_broadcast(&cond_); FALSE_LOG_MSG(ret == 0, "NotifyAll failed with errno = " PUBLIC_LOG_D32, ret); } void ConditionVariable::Wait(AutoLock& lock) noexcept { FALSE_RETURN_MSG(condInited_, "Wait uninitialized pthread cond"); pthread_cond_wait(&cond_, &(lock.mutex_->nativeHandle_)); } void ConditionVariable::Wait(AutoLock& lock, std::function pred) noexcept { FALSE_RETURN_MSG(condInited_, "Wait uninitialized pthread cond"); while (!pred()) { Wait(lock); } } bool ConditionVariable::WaitFor(AutoLock& lock, int64_t timeoutMs) { FALSE_RETURN_V_MSG_E(timeoutMs >= 0, false, "ConditionVariable WaitUntil invalid timeoutMs: " PUBLIC_LOG_D64, timeoutMs); FALSE_RETURN_V_MSG_E(condInited_, false, "WaitFor uninitialized pthread cond"); struct timespec timeout = {0, 0}; #ifdef USING_CLOCK_REALTIME clock_gettime(CLOCK_REALTIME, &timeout); #else clock_gettime(CLOCK_MONOTONIC, &timeout); #endif timeout = NsToTm(TmToNs(timeout) + timeoutMs * std::mega::num); return pthread_cond_timedwait(&cond_, &(lock.mutex_->nativeHandle_), &timeout) == 0; } bool ConditionVariable::WaitFor(AutoLock& lock, int64_t timeoutMs, std::function pred) { FALSE_RETURN_V_MSG_E(timeoutMs >= 0, false, "ConditionVariable WaitUntil invalid timeoutMs: " PUBLIC_LOG_D64, timeoutMs); FALSE_RETURN_V_MSG_E(condInited_, false, "WaitFor uninitialized pthread cond"); struct timespec timeout = {0, 0}; #ifdef USING_CLOCK_REALTIME clock_gettime(CLOCK_REALTIME, &timeout); #else clock_gettime(CLOCK_MONOTONIC, &timeout); #endif timeout = NsToTm(TmToNs(timeout) + timeoutMs * std::mega::num); int status = 0; while (!pred() && (status == 0)) { status = pthread_cond_timedwait(&cond_, &(lock.mutex_->nativeHandle_), &timeout); if (status == ETIMEDOUT) { return pred(); } } return status == 0; } } // namespace Media } // namespace OHOS