1 /*
2  * Copyright (C) 2022 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 "hks_condition.h"
17 
18 #include "hks_mem.h"
19 #include "hks_template.h"
20 
21 #include <errno.h>
22 #include <pthread.h>
23 #include <stdatomic.h>
24 #include <stdbool.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 struct HksCondition {
33     volatile atomic_bool notified;
34     pthread_mutex_t mutex;
35     pthread_cond_t cond;
36 };
37 
HksConditionWait(HksCondition *condition)38 int32_t HksConditionWait(HksCondition *condition)
39 {
40     HKS_IF_NULL_LOGE_RETURN(condition, -1, "HksConditionWait condition is NULL!")
41 
42     int32_t ret = pthread_mutex_lock(&condition->mutex);
43     if (ret != 0) {
44         HKS_LOG_ERRNO("HksConditionWait pthread_mutex_lock fail!", ret);
45         return ret;
46     }
47     if (atomic_load(&condition->notified)) {
48         int unlockRet = pthread_mutex_unlock(&condition->mutex);
49         if (unlockRet != 0) {
50             HKS_LOG_ERRNO("HksConditionWait notified pthread_mutex_unlock fail!", unlockRet);
51         }
52         return 0;
53     } else {
54         HKS_LOG_I("HksConditionWait begin wait...");
55         ret = pthread_cond_wait(&condition->cond, &condition->mutex);
56         if (ret != 0) {
57             HKS_LOG_ERRNO("HksConditionWait pthread_cond_wait fail!", ret);
58         }
59         int unlockRet = pthread_mutex_unlock(&condition->mutex);
60         if (unlockRet != 0) {
61             HKS_LOG_ERRNO("HksConditionWait waited pthread_mutex_unlock fail!", unlockRet);
62         }
63         return ret;
64     }
65 }
66 
HksConditionNotify(HksCondition *condition)67 int32_t HksConditionNotify(HksCondition *condition)
68 {
69     HKS_IF_NULL_LOGE_RETURN(condition, -1, "HksConditionNotify condition is NULL!")
70 
71     int32_t ret = pthread_mutex_lock(&condition->mutex);
72     if (ret != 0) {
73         HKS_LOG_ERRNO("HksConditionNotify pthread_mutex_lock fail!", ret);
74         return ret;
75     }
76 
77     bool flag = false;
78     if (atomic_compare_exchange_strong(&condition->notified, &flag, true)) {
79         HKS_LOG_I("never pthread_cond_signal before, first time notify!");
80     } else {
81         HKS_LOG_W("do pthread_cond_signal again!");
82     }
83 
84     ret = pthread_cond_signal(&condition->cond);
85     if (ret != 0) {
86         HKS_LOG_ERRNO("HksConditionNotify pthread_cond_signal fail!", ret);
87     }
88     int unlockRet = pthread_mutex_unlock(&condition->mutex);
89     if (unlockRet != 0) {
90         HKS_LOG_ERRNO("HksConditionNotify pthread_mutex_unlock fail!", unlockRet);
91     }
92     return ret;
93 }
94 
HksConditionNotifyAll(HksCondition *condition)95 int32_t HksConditionNotifyAll(HksCondition *condition)
96 {
97     HKS_IF_NULL_LOGE_RETURN(condition, -1, "HksConditionNotifyAll condition is NULL!")
98 
99     int32_t ret = pthread_mutex_lock(&condition->mutex);
100     if (ret != 0) {
101         HKS_LOG_ERRNO("HksConditionNotifyAll pthread_mutex_lock fail!", ret);
102         return ret;
103     }
104 
105     bool flag = false;
106     if (atomic_compare_exchange_strong(&condition->notified, &flag, true)) {
107         HKS_LOG_I("never pthread_cond_broadcast before, first time notify!");
108     } else {
109         HKS_LOG_W("do pthread_cond_broadcast again!");
110     }
111 
112     ret = pthread_cond_broadcast(&condition->cond);
113     if (ret != 0) {
114         HKS_LOG_ERRNO("HksConditionNotifyAll pthread_cond_broadcast fail!", ret);
115     }
116     int unlockRet = pthread_mutex_unlock(&condition->mutex);
117     if (unlockRet != 0) {
118         HKS_LOG_ERRNO("HksConditionNotifyAll pthread_mutex_unlock fail!", unlockRet);
119     }
120     return ret;
121 }
122 
HksConditionCreate(void)123 HksCondition *HksConditionCreate(void)
124 {
125     HksCondition *condition = (HksCondition *)HksMalloc(sizeof(HksCondition));
126     HKS_IF_NULL_RETURN(condition, NULL)
127     atomic_store(&condition->notified, false);
128     int32_t ret = pthread_mutex_init(&condition->mutex, NULL);
129     if (ret != 0) {
130         HKS_LOG_ERRNO("HksConditionCreate pthread_mutex_init fail!", ret);
131         HKS_FREE(condition);
132         return NULL;
133     }
134 
135     pthread_condattr_t attr;
136     int attrRet = pthread_condattr_init(&attr);
137     if (attrRet != 0) {
138         HKS_LOG_ERRNO("HksConditionCreate pthread_condattr_init fail!", attrRet);
139     }
140     ret = pthread_cond_init(&condition->cond, &attr);
141     attrRet = pthread_condattr_destroy(&attr);
142     if (attrRet != 0) {
143         HKS_LOG_ERRNO("HksConditionCreate pthread_condattr_destroy fail!", attrRet);
144     }
145     if (ret != 0) {
146         HKS_LOG_ERRNO("HksConditionCreate pthread_cond_init fail!", ret);
147         pthread_mutex_destroy(&condition->mutex);
148         HKS_FREE(condition);
149         return NULL;
150     }
151     return condition;
152 }
153 
HksConditionDestroy(HksCondition* condition)154 void HksConditionDestroy(HksCondition* condition)
155 {
156     if (condition == NULL) {
157         HKS_LOG_E("HksConditionDestroy condition is NULL!");
158         return;
159     }
160     int ret = pthread_mutex_destroy(&condition->mutex);
161     if (ret != 0) {
162         HKS_LOG_ERRNO("HksConditionDestroy pthread_mutex_destroy fail!", ret);
163     }
164     ret = pthread_cond_destroy(&condition->cond);
165     if (ret != 0) {
166         HKS_LOG_ERRNO("HksConditionDestroy pthread_cond_destroy fail!", ret);
167     }
168     HKS_FREE(condition);
169 }
170 
171 #ifdef __cplusplus
172 }
173 #endif