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 #include "cpp/condition_variable.h"
17 #include "c/condition_variable.h"
18 #include "sync/wait_queue.h"
19 #include "sync/mutex_private.h"
20 #include "internal_inc/osal.h"
21 #include "dfx/log/ffrt_log_api.h"
22 
23 namespace ffrt {
24 using condition_variable_private = WaitQueue;
25 }
26 
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30 API_ATTRIBUTE((visibility("default")))
31 int ffrt_cond_init(ffrt_cond_t* cond, const ffrt_condattr_t* attr)
32 {
33     if (!cond) {
34         FFRT_LOGE("cond should not be empty");
35         return ffrt_error_inval;
36     }
37     static_assert(sizeof(ffrt::condition_variable_private) <= ffrt_cond_storage_size,
38         "size must be less than ffrt_cond_storage_size");
39 
40     new (cond) ffrt::condition_variable_private();
41     return ffrt_success;
42 }
43 
44 API_ATTRIBUTE((visibility("default")))
45 int ffrt_cond_signal(ffrt_cond_t* cond)
46 {
47     if (!cond) {
48         FFRT_LOGE("cond should not be empty");
49         return ffrt_error_inval;
50     }
51     auto p = reinterpret_cast<ffrt::condition_variable_private *>(cond);
52     p->NotifyOne();
53     return ffrt_success;
54 }
55 
56 API_ATTRIBUTE((visibility("default")))
57 int ffrt_cond_broadcast(ffrt_cond_t* cond)
58 {
59     if (!cond) {
60         FFRT_LOGE("cond should not be empty");
61         return ffrt_error_inval;
62     }
63     auto p = reinterpret_cast<ffrt::condition_variable_private *>(cond);
64     p->NotifyAll();
65     return ffrt_success;
66 }
67 
68 API_ATTRIBUTE((visibility("default")))
69 int ffrt_cond_wait(ffrt_cond_t* cond, ffrt_mutex_t* mutex)
70 {
71     if (!cond || !mutex) {
72         FFRT_LOGE("cond and mutex should not be empty");
73         return ffrt_error_inval;
74     }
75     auto pc = reinterpret_cast<ffrt::condition_variable_private *>(cond);
76     auto pm = reinterpret_cast<ffrt::mutexPrivate *>(mutex);
77     pc->SuspendAndWait(pm);
78     return ffrt_success;
79 }
80 
81 API_ATTRIBUTE((visibility("default")))
82 int ffrt_cond_timedwait(ffrt_cond_t* cond, ffrt_mutex_t* mutex, const struct timespec* time_point)
83 {
84     if (!cond || !mutex || !time_point) {
85         FFRT_LOGE("cond, mutex and time_point should not be empty");
86         return ffrt_error_inval;
87     }
88     auto pc = reinterpret_cast<ffrt::condition_variable_private *>(cond);
89     auto pm = reinterpret_cast<ffrt::mutexPrivate *>(mutex);
90 
91     using namespace std::chrono;
92     auto duration = seconds{ time_point->tv_sec } + nanoseconds{ time_point->tv_nsec };
93     auto tp = ffrt::TimePoint {
94         duration_cast<steady_clock::duration>(duration_cast<nanoseconds>(duration))
95     };
96 
97     return pc->SuspendAndWaitUntil(pm, tp) ? ffrt_error_timedout : ffrt_success;
98 }
99 
100 API_ATTRIBUTE((visibility("default")))
101 int ffrt_cond_destroy(ffrt_cond_t* cond)
102 {
103     if (!cond) {
104         FFRT_LOGE("cond should not be empty");
105         return ffrt_error_inval;
106     }
107     auto p = reinterpret_cast<ffrt::condition_variable_private *>(cond);
108     p->~WaitQueue();
109     return ffrt_success;
110 }
111 #ifdef __cplusplus
112 }
113 #endif
114