1 /*
2  * Copyright (c) 2021-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 #define HST_LOG_TAG "ConditionVariable"
17 
18 #include "osal/task/condition_variable.h"
19 #include <ratio>
20 #include <ctime>
21 #include "common/log.h"
22 
23 namespace {
24 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "ConditionVariable" };
25 }
26 
27 namespace {
TmToNs(struct timespec tm)28 inline long long TmToNs(struct timespec tm)
29 {
30     return tm.tv_sec * std::giga::num + tm.tv_nsec;
31 }
32 
NsToTm(long long ns)33 inline struct timespec NsToTm(long long ns)
34 {
35     return {ns / std::giga::num, static_cast<long>(ns % std::giga::num)};
36 }
37 }
38 
39 namespace OHOS {
40 namespace Media {
ConditionVariable()41 ConditionVariable::ConditionVariable() noexcept : condInited_(true)
42 {
43     pthread_condattr_t attr;
44     pthread_condattr_init(&attr);
45 #ifndef __LITEOS_M__
46 #ifdef USING_CLOCK_REALTIME
47     pthread_condattr_setclock(&attr, CLOCK_REALTIME);
48 #else
49     pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
50 #endif
51 #endif
52     int rtv = pthread_cond_init(&cond_, &attr);
53     if (rtv != 0) {
54         condInited_ = false;
55         MEDIA_LOG_E("failed to init pthread cond variable");
56     }
57     pthread_condattr_destroy(&attr);
58 }
59 
~ConditionVariable()60 ConditionVariable::~ConditionVariable() noexcept
61 {
62     if (condInited_) {
63         pthread_cond_destroy(&cond_);
64     }
65 }
66 
NotifyOne()67 void ConditionVariable::NotifyOne() noexcept
68 {
69     FALSE_RETURN_MSG(condInited_, "NotifyOne uninitialized pthread cond");
70     int ret = pthread_cond_signal(&cond_);
71     FALSE_LOG_MSG(ret == 0, "NotifyOne failed with errno = " PUBLIC_LOG_D32, ret);
72 }
73 
NotifyAll()74 void ConditionVariable::NotifyAll() noexcept
75 {
76     FALSE_RETURN_MSG(condInited_, "NotifyAll uninitialized pthread cond");
77     int ret = pthread_cond_broadcast(&cond_);
78     FALSE_LOG_MSG(ret == 0, "NotifyAll failed with errno = " PUBLIC_LOG_D32, ret);
79 }
80 
Wait(AutoLock & lock)81 void ConditionVariable::Wait(AutoLock& lock) noexcept
82 {
83     FALSE_RETURN_MSG(condInited_, "Wait uninitialized pthread cond");
84     pthread_cond_wait(&cond_, &(lock.mutex_->nativeHandle_));
85 }
86 
Wait(AutoLock & lock,std::function<bool ()> pred)87 void ConditionVariable::Wait(AutoLock& lock, std::function<bool()> pred) noexcept
88 {
89     FALSE_RETURN_MSG(condInited_, "Wait uninitialized pthread cond");
90     while (!pred()) {
91         Wait(lock);
92     }
93 }
94 
WaitFor(AutoLock & lock,int64_t timeoutMs)95 bool ConditionVariable::WaitFor(AutoLock& lock, int64_t timeoutMs)
96 {
97     FALSE_RETURN_V_MSG_E(timeoutMs >= 0,
98         false, "ConditionVariable WaitUntil invalid timeoutMs: " PUBLIC_LOG_D64, timeoutMs);
99     FALSE_RETURN_V_MSG_E(condInited_,
100         false, "WaitFor uninitialized pthread cond");
101     struct timespec timeout = {0, 0};
102 #ifdef USING_CLOCK_REALTIME
103     clock_gettime(CLOCK_REALTIME, &timeout);
104 #else
105     clock_gettime(CLOCK_MONOTONIC, &timeout);
106 #endif
107     timeout = NsToTm(TmToNs(timeout) + timeoutMs * std::mega::num);
108     return pthread_cond_timedwait(&cond_, &(lock.mutex_->nativeHandle_), &timeout) == 0;
109 }
110 
WaitFor(AutoLock & lock,int64_t timeoutMs,std::function<bool ()> pred)111 bool ConditionVariable::WaitFor(AutoLock& lock, int64_t timeoutMs, std::function<bool()> pred)
112 {
113     FALSE_RETURN_V_MSG_E(timeoutMs >= 0,
114         false, "ConditionVariable WaitUntil invalid timeoutMs: " PUBLIC_LOG_D64, timeoutMs);
115     FALSE_RETURN_V_MSG_E(condInited_,
116         false, "WaitFor uninitialized pthread cond");
117     struct timespec timeout = {0, 0};
118 #ifdef USING_CLOCK_REALTIME
119     clock_gettime(CLOCK_REALTIME, &timeout);
120 #else
121     clock_gettime(CLOCK_MONOTONIC, &timeout);
122 #endif
123    timeout = NsToTm(TmToNs(timeout) + timeoutMs * std::mega::num);
124     int status = 0;
125     while (!pred() && (status == 0)) {
126         status = pthread_cond_timedwait(&cond_, &(lock.mutex_->nativeHandle_), &timeout);
127         if (status == ETIMEDOUT) {
128             return pred();
129         }
130     }
131     return status == 0;
132 }
133 } // namespace Media
134 } // namespace OHOS
135