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