1 /*
2  * Copyright (c) 2021-2021 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 "foundation/osal/thread/condition_variable.h"
19 #include <ratio>
20 #include "foundation/log.h"
21 
22 namespace {
TmToNs(struct timespec tm)23 inline long long TmToNs(struct timespec tm)
24 {
25     return tm.tv_sec * std::giga::num + tm.tv_nsec;
26 }
27 
NsToTm(long long ns)28 inline struct timespec NsToTm(long long ns)
29 {
30     return {ns / std::giga::num, static_cast<long>(ns % std::giga::num)};
31 }
32 }
33 
34 namespace OHOS {
35 namespace Media {
36 namespace OSAL {
ConditionVariable()37 ConditionVariable::ConditionVariable() noexcept : condInited_(true)
38 {
39     pthread_condattr_t attr;
40     pthread_condattr_init(&attr);
41 #ifndef __LITEOS_M__
42 #ifdef USING_CLOCK_REALTIME
43     pthread_condattr_setclock(&attr, CLOCK_REALTIME);
44 #else
45     pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
46 #endif
47 #endif
48     int rtv = pthread_cond_init(&cond_, &attr);
49     if (rtv != 0) {
50         condInited_ = false;
51         MEDIA_LOG_E("failed to init pthread cond variable");
52     }
53     MEDIA_LOG_D("succeed to init pthread cond variable");
54     pthread_condattr_destroy(&attr);
55 }
56 
~ConditionVariable()57 ConditionVariable::~ConditionVariable() noexcept
58 {
59     if (condInited_) {
60         pthread_cond_destroy(&cond_);
61     }
62 }
63 
NotifyOne()64 void ConditionVariable::NotifyOne() noexcept
65 {
66     int ret = pthread_cond_signal(&cond_);
67     if (ret != 0) {
68         MEDIA_LOG_E("NotifyOne failed with errno = " PUBLIC_LOG_D32, ret);
69     }
70     MEDIA_LOG_D("NotifyOne succeed");
71 }
72 
NotifyAll()73 void ConditionVariable::NotifyAll() noexcept
74 {
75     int ret = pthread_cond_broadcast(&cond_);
76     if (ret != 0) {
77         MEDIA_LOG_E("NotifyAll failed with errno = " PUBLIC_LOG_D32, ret);
78     }
79     MEDIA_LOG_D("NotifyAll succeed");
80 }
81 
Wait(ScopedLock & lock)82 void ConditionVariable::Wait(ScopedLock& lock) noexcept
83 {
84     pthread_cond_wait(&cond_, &(lock.mutex_->nativeHandle_));
85 }
86 
WaitFor(ScopedLock & lock,int timeoutMs)87 bool ConditionVariable::WaitFor(ScopedLock& lock, int timeoutMs)
88 {
89     if (timeoutMs < 0) {
90         MEDIA_LOG_E("ConditionVariable WaitUntil invalid timeoutMs: " PUBLIC_LOG_D32, timeoutMs);
91         return false;
92     }
93     struct timespec timeout = {0, 0};
94 #ifdef USING_CLOCK_REALTIME
95     clock_gettime(CLOCK_REALTIME, &timeout);
96 #else
97     clock_gettime(CLOCK_MONOTONIC, &timeout);
98 #endif
99     timeout = NsToTm(TmToNs(timeout) + timeoutMs * std::mega::num);
100     return pthread_cond_timedwait(&cond_, &(lock.mutex_->nativeHandle_),
101         &timeout) == 0;
102 }
103 } // namespace OSAL
104 } // namespace Media
105 } // namespace OHOS
106