1 /*
2  * Copyright (c) 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 /**
17  * @file condition_variable.h
18  *
19  * @brief Declares the condition variable interfaces in C++.
20  *
21  * @since 10
22  * @version 1.0
23  */
24 #ifndef FFRT_API_CPP_CONDITION_VARIABLE_H
25 #define FFRT_API_CPP_CONDITION_VARIABLE_H
26 #include <chrono>
27 #include <mutex>
28 #include "mutex.h"
29 #include "c/condition_variable.h"
30 
31 namespace ffrt {
32 enum class cv_status { no_timeout, timeout };
33 
34 class condition_variable : public ffrt_cond_t {
35 public:
condition_variable()36     condition_variable()
37     {
38         ffrt_cond_init(this, nullptr);
39     }
40 
~condition_variable()41     ~condition_variable() noexcept
42     {
43         ffrt_cond_destroy(this);
44     }
45 
46     condition_variable(const condition_variable&) = delete;
47     condition_variable& operator=(const condition_variable&) = delete;
48 
49     template <typename Clock, typename Duration, typename Pred>
wait_until(std::unique_lock<mutex> & lk,const std::chrono::time_point<Clock,Duration> & tp,Pred && pred)50     bool wait_until(
51         std::unique_lock<mutex>& lk, const std::chrono::time_point<Clock, Duration>& tp, Pred&& pred) noexcept
52     {
53         while (!pred()) {
54             if (wait_until(lk, tp) == cv_status::timeout) {
55                 return pred();
56             }
57         }
58         return true;
59     }
60 
61     template <typename Clock, typename Duration>
wait_until(std::unique_lock<mutex> & lk,const std::chrono::time_point<Clock,Duration> & tp)62     cv_status wait_until(std::unique_lock<mutex>& lk, const std::chrono::time_point<Clock, Duration>& tp) noexcept
63     {
64         return _wait_for(lk, tp - Clock::now());
65     }
66 
67     template <typename Rep, typename Period>
wait_for(std::unique_lock<mutex> & lk,const std::chrono::duration<Rep,Period> & sleep_time)68     cv_status wait_for(std::unique_lock<mutex>& lk, const std::chrono::duration<Rep, Period>& sleep_time) noexcept
69     {
70         return _wait_for(lk, sleep_time);
71     }
72 
73     template <typename Rep, typename Period, typename Pred>
wait_for(std::unique_lock<mutex> & lk,const std::chrono::duration<Rep,Period> & sleepTime,Pred && pred)74     bool wait_for(
75         std::unique_lock<mutex>& lk, const std::chrono::duration<Rep, Period>& sleepTime, Pred&& pred) noexcept
76     {
77         return wait_until(lk, std::chrono::steady_clock::now() + sleepTime, std::forward<Pred>(pred));
78     }
79 
80     template <typename Pred>
wait(std::unique_lock<mutex> & lk,Pred && pred)81     void wait(std::unique_lock<mutex>& lk, Pred&& pred)
82     {
83         while (!pred()) {
84             wait(lk);
85         }
86     }
87 
wait(std::unique_lock<mutex> & lk)88     void wait(std::unique_lock<mutex>& lk)
89     {
90         ffrt_cond_wait(this, lk.mutex());
91     }
92 
notify_one()93     void notify_one() noexcept
94     {
95         ffrt_cond_signal(this);
96     }
97 
notify_all()98     void notify_all() noexcept
99     {
100         ffrt_cond_broadcast(this);
101     }
102 
103 private:
104     template <typename Rep, typename Period>
_wait_for(std::unique_lock<mutex> & lk,const std::chrono::duration<Rep,Period> & dur)105     cv_status _wait_for(std::unique_lock<mutex>& lk, const std::chrono::duration<Rep, Period>& dur) noexcept
106     {
107         timespec ts;
108         std::chrono::nanoseconds ns = std::chrono::steady_clock::now().time_since_epoch();
109         ns += std::chrono::duration_cast<std::chrono::nanoseconds>(dur);
110         ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(ns).count();
111         ns -= std::chrono::seconds(ts.tv_sec);
112         ts.tv_nsec = static_cast<long>(ns.count());
113 
114         auto ret = ffrt_cond_timedwait(this, lk.mutex(), &ts);
115         if (ret == ffrt_success) {
116             return cv_status::no_timeout;
117         }
118         return cv_status::timeout;
119     }
120 };
121 } // namespace ffrt
122 #endif
123