1fa7767c5Sopenharmony_ci/*
2fa7767c5Sopenharmony_ci * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3fa7767c5Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fa7767c5Sopenharmony_ci * you may not use this file except in compliance with the License.
5fa7767c5Sopenharmony_ci * You may obtain a copy of the License at
6fa7767c5Sopenharmony_ci *
7fa7767c5Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8fa7767c5Sopenharmony_ci *
9fa7767c5Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fa7767c5Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fa7767c5Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fa7767c5Sopenharmony_ci * See the License for the specific language governing permissions and
13fa7767c5Sopenharmony_ci * limitations under the License.
14fa7767c5Sopenharmony_ci */
15fa7767c5Sopenharmony_ci
16fa7767c5Sopenharmony_ci#define HST_LOG_TAG "ConditionVariable"
17fa7767c5Sopenharmony_ci
18fa7767c5Sopenharmony_ci#include "osal/task/condition_variable.h"
19fa7767c5Sopenharmony_ci#include <ratio>
20fa7767c5Sopenharmony_ci#include <ctime>
21fa7767c5Sopenharmony_ci#include "common/log.h"
22fa7767c5Sopenharmony_ci
23fa7767c5Sopenharmony_cinamespace {
24fa7767c5Sopenharmony_ciconstexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "ConditionVariable" };
25fa7767c5Sopenharmony_ci}
26fa7767c5Sopenharmony_ci
27fa7767c5Sopenharmony_cinamespace {
28fa7767c5Sopenharmony_ciinline long long TmToNs(struct timespec tm)
29fa7767c5Sopenharmony_ci{
30fa7767c5Sopenharmony_ci    return tm.tv_sec * std::giga::num + tm.tv_nsec;
31fa7767c5Sopenharmony_ci}
32fa7767c5Sopenharmony_ci
33fa7767c5Sopenharmony_ciinline struct timespec NsToTm(long long ns)
34fa7767c5Sopenharmony_ci{
35fa7767c5Sopenharmony_ci    return {ns / std::giga::num, static_cast<long>(ns % std::giga::num)};
36fa7767c5Sopenharmony_ci}
37fa7767c5Sopenharmony_ci}
38fa7767c5Sopenharmony_ci
39fa7767c5Sopenharmony_cinamespace OHOS {
40fa7767c5Sopenharmony_cinamespace Media {
41fa7767c5Sopenharmony_ciConditionVariable::ConditionVariable() noexcept : condInited_(true)
42fa7767c5Sopenharmony_ci{
43fa7767c5Sopenharmony_ci    pthread_condattr_t attr;
44fa7767c5Sopenharmony_ci    pthread_condattr_init(&attr);
45fa7767c5Sopenharmony_ci#ifndef __LITEOS_M__
46fa7767c5Sopenharmony_ci#ifdef USING_CLOCK_REALTIME
47fa7767c5Sopenharmony_ci    pthread_condattr_setclock(&attr, CLOCK_REALTIME);
48fa7767c5Sopenharmony_ci#else
49fa7767c5Sopenharmony_ci    pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
50fa7767c5Sopenharmony_ci#endif
51fa7767c5Sopenharmony_ci#endif
52fa7767c5Sopenharmony_ci    int rtv = pthread_cond_init(&cond_, &attr);
53fa7767c5Sopenharmony_ci    if (rtv != 0) {
54fa7767c5Sopenharmony_ci        condInited_ = false;
55fa7767c5Sopenharmony_ci        MEDIA_LOG_E("failed to init pthread cond variable");
56fa7767c5Sopenharmony_ci    }
57fa7767c5Sopenharmony_ci    pthread_condattr_destroy(&attr);
58fa7767c5Sopenharmony_ci}
59fa7767c5Sopenharmony_ci
60fa7767c5Sopenharmony_ciConditionVariable::~ConditionVariable() noexcept
61fa7767c5Sopenharmony_ci{
62fa7767c5Sopenharmony_ci    if (condInited_) {
63fa7767c5Sopenharmony_ci        pthread_cond_destroy(&cond_);
64fa7767c5Sopenharmony_ci    }
65fa7767c5Sopenharmony_ci}
66fa7767c5Sopenharmony_ci
67fa7767c5Sopenharmony_civoid ConditionVariable::NotifyOne() noexcept
68fa7767c5Sopenharmony_ci{
69fa7767c5Sopenharmony_ci    FALSE_RETURN_MSG(condInited_, "NotifyOne uninitialized pthread cond");
70fa7767c5Sopenharmony_ci    int ret = pthread_cond_signal(&cond_);
71fa7767c5Sopenharmony_ci    FALSE_LOG_MSG(ret == 0, "NotifyOne failed with errno = " PUBLIC_LOG_D32, ret);
72fa7767c5Sopenharmony_ci}
73fa7767c5Sopenharmony_ci
74fa7767c5Sopenharmony_civoid ConditionVariable::NotifyAll() noexcept
75fa7767c5Sopenharmony_ci{
76fa7767c5Sopenharmony_ci    FALSE_RETURN_MSG(condInited_, "NotifyAll uninitialized pthread cond");
77fa7767c5Sopenharmony_ci    int ret = pthread_cond_broadcast(&cond_);
78fa7767c5Sopenharmony_ci    FALSE_LOG_MSG(ret == 0, "NotifyAll failed with errno = " PUBLIC_LOG_D32, ret);
79fa7767c5Sopenharmony_ci}
80fa7767c5Sopenharmony_ci
81fa7767c5Sopenharmony_civoid ConditionVariable::Wait(AutoLock& lock) noexcept
82fa7767c5Sopenharmony_ci{
83fa7767c5Sopenharmony_ci    FALSE_RETURN_MSG(condInited_, "Wait uninitialized pthread cond");
84fa7767c5Sopenharmony_ci    pthread_cond_wait(&cond_, &(lock.mutex_->nativeHandle_));
85fa7767c5Sopenharmony_ci}
86fa7767c5Sopenharmony_ci
87fa7767c5Sopenharmony_civoid ConditionVariable::Wait(AutoLock& lock, std::function<bool()> pred) noexcept
88fa7767c5Sopenharmony_ci{
89fa7767c5Sopenharmony_ci    FALSE_RETURN_MSG(condInited_, "Wait uninitialized pthread cond");
90fa7767c5Sopenharmony_ci    while (!pred()) {
91fa7767c5Sopenharmony_ci        Wait(lock);
92fa7767c5Sopenharmony_ci    }
93fa7767c5Sopenharmony_ci}
94fa7767c5Sopenharmony_ci
95fa7767c5Sopenharmony_cibool ConditionVariable::WaitFor(AutoLock& lock, int64_t timeoutMs)
96fa7767c5Sopenharmony_ci{
97fa7767c5Sopenharmony_ci    FALSE_RETURN_V_MSG_E(timeoutMs >= 0,
98fa7767c5Sopenharmony_ci        false, "ConditionVariable WaitUntil invalid timeoutMs: " PUBLIC_LOG_D64, timeoutMs);
99fa7767c5Sopenharmony_ci    FALSE_RETURN_V_MSG_E(condInited_,
100fa7767c5Sopenharmony_ci        false, "WaitFor uninitialized pthread cond");
101fa7767c5Sopenharmony_ci    struct timespec timeout = {0, 0};
102fa7767c5Sopenharmony_ci#ifdef USING_CLOCK_REALTIME
103fa7767c5Sopenharmony_ci    clock_gettime(CLOCK_REALTIME, &timeout);
104fa7767c5Sopenharmony_ci#else
105fa7767c5Sopenharmony_ci    clock_gettime(CLOCK_MONOTONIC, &timeout);
106fa7767c5Sopenharmony_ci#endif
107fa7767c5Sopenharmony_ci    timeout = NsToTm(TmToNs(timeout) + timeoutMs * std::mega::num);
108fa7767c5Sopenharmony_ci    return pthread_cond_timedwait(&cond_, &(lock.mutex_->nativeHandle_), &timeout) == 0;
109fa7767c5Sopenharmony_ci}
110fa7767c5Sopenharmony_ci
111fa7767c5Sopenharmony_cibool ConditionVariable::WaitFor(AutoLock& lock, int64_t timeoutMs, std::function<bool()> pred)
112fa7767c5Sopenharmony_ci{
113fa7767c5Sopenharmony_ci    FALSE_RETURN_V_MSG_E(timeoutMs >= 0,
114fa7767c5Sopenharmony_ci        false, "ConditionVariable WaitUntil invalid timeoutMs: " PUBLIC_LOG_D64, timeoutMs);
115fa7767c5Sopenharmony_ci    FALSE_RETURN_V_MSG_E(condInited_,
116fa7767c5Sopenharmony_ci        false, "WaitFor uninitialized pthread cond");
117fa7767c5Sopenharmony_ci    struct timespec timeout = {0, 0};
118fa7767c5Sopenharmony_ci#ifdef USING_CLOCK_REALTIME
119fa7767c5Sopenharmony_ci    clock_gettime(CLOCK_REALTIME, &timeout);
120fa7767c5Sopenharmony_ci#else
121fa7767c5Sopenharmony_ci    clock_gettime(CLOCK_MONOTONIC, &timeout);
122fa7767c5Sopenharmony_ci#endif
123fa7767c5Sopenharmony_ci    timeout = NsToTm(TmToNs(timeout) + timeoutMs * std::mega::num);
124fa7767c5Sopenharmony_ci    int status = 0;
125fa7767c5Sopenharmony_ci    while (!pred() && (status == 0)) {
126fa7767c5Sopenharmony_ci        status = pthread_cond_timedwait(&cond_, &(lock.mutex_->nativeHandle_), &timeout);
127fa7767c5Sopenharmony_ci        if (status == ETIMEDOUT) {
128fa7767c5Sopenharmony_ci            return pred();
129fa7767c5Sopenharmony_ci        }
130fa7767c5Sopenharmony_ci    }
131fa7767c5Sopenharmony_ci    return status == 0;
132fa7767c5Sopenharmony_ci}
133fa7767c5Sopenharmony_ci} // namespace Media
134fa7767c5Sopenharmony_ci} // namespace OHOS
135