1/* 2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. 3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this list of 9 * conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 * of conditions and the following disclaimer in the documentation and/or other materials 13 * provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used 16 * to endorse or promote products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <errno.h> 33#include <pthread.h> 34#include <stdlib.h> 35#include <unistd.h> 36#include <securec.h> 37#include "los_config.h" 38#include "los_task.h" 39#include "los_swtmr.h" 40#include "time_internal.h" 41#include "los_atomic.h" 42#include "los_event.h" 43#include "los_mux.h" 44 45#define INLINE inline 46 47#define BROADCAST_EVENT 1 48#define COND_COUNTER_STEP 0x0004U 49#define COND_FLAGS_MASK 0x0003U 50#define COND_COUNTER_MASK (~COND_FLAGS_MASK) 51 52int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *shared) 53{ 54 if ((attr == NULL) || (shared == NULL)) { 55 return EINVAL; 56 } 57 58 *shared = PTHREAD_PROCESS_PRIVATE; 59 60 return 0; 61} 62 63int pthread_condattr_setpshared(pthread_condattr_t *attr, int shared) 64{ 65 (VOID)attr; 66 if ((shared != PTHREAD_PROCESS_PRIVATE) && (shared != PTHREAD_PROCESS_SHARED)) { 67 return EINVAL; 68 } 69 70 if (shared != PTHREAD_PROCESS_PRIVATE) { 71 return ENOSYS; 72 } 73 74 return 0; 75} 76 77int pthread_condattr_destroy(pthread_condattr_t *attr) 78{ 79 if (attr == NULL) { 80 return EINVAL; 81 } 82 83 (VOID)memset_s(attr, sizeof(pthread_condattr_t), 0, sizeof(pthread_condattr_t)); 84 attr->clock = INT32_MAX; 85 86 return 0; 87} 88 89int pthread_condattr_getclock(const pthread_condattr_t *attr, clockid_t *clock) 90{ 91 if ((attr == NULL) || (clock == NULL)) { 92 return -1; 93 } 94 95 *clock = attr->clock; 96 97 return 0; 98} 99 100int pthread_condattr_init(pthread_condattr_t *attr) 101{ 102 if (attr == NULL) { 103 return EINVAL; 104 } 105 106 attr->clock = CLOCK_REALTIME; 107 108 return 0; 109} 110 111int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clk) 112{ 113 if ((attr == NULL) || (clk < 0)) { 114 return EINVAL; 115 } 116 117 if ((clk != CLOCK_REALTIME) && (clk != CLOCK_MONOTONIC) && 118 (clk != CLOCK_PROCESS_CPUTIME_ID) && (clk != CLOCK_THREAD_CPUTIME_ID)) { 119 return EINVAL; 120 } 121 122 attr->clock = clk; 123 124 return 0; 125} 126 127STATIC INLINE INT32 CondInitCheck(const pthread_cond_t *cond) 128{ 129 if ((cond->event.stEventList.pstPrev == NULL) && 130 (cond->event.stEventList.pstNext == NULL)) { 131 return 1; 132 } 133 134 return 0; 135} 136 137int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) 138{ 139 int ret = 0; 140 pthread_condattr_t condAttr; 141 142 if (cond == NULL) { 143 return EINVAL; 144 } 145 146 if (attr == NULL) { 147 pthread_condattr_init(&condAttr); 148 attr = &condAttr; 149 } 150 151 (VOID)LOS_EventInit(&(cond->event)); 152 153 cond->mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); 154 if (cond->mutex == NULL) { 155 return ENOMEM; 156 } 157 158 (VOID)pthread_mutex_init(cond->mutex, NULL); 159 160 cond->value = 0; 161 (VOID)pthread_mutex_lock(cond->mutex); 162 cond->count = 0; 163 cond->clock = attr->clock; 164 (VOID)pthread_mutex_unlock(cond->mutex); 165 166 return ret; 167} 168 169int pthread_cond_destroy(pthread_cond_t *cond) 170{ 171 if (cond == NULL) { 172 return EINVAL; 173 } 174 175 if (CondInitCheck(cond)) { 176 return 0; 177 } 178 179 if (LOS_EventDestroy(&cond->event) != LOS_OK) { 180 return EBUSY; 181 } 182 if (pthread_mutex_destroy(cond->mutex) != 0) { 183 PRINT_ERR("%s mutex destroy fail!\n", __FUNCTION__); 184 return EINVAL; 185 } 186 free(cond->mutex); 187 cond->mutex = NULL; 188 189 return 0; 190} 191 192STATIC VOID PthreadCountSub(pthread_cond_t *cond) 193{ 194 (VOID)pthread_mutex_lock(cond->mutex); 195 if (cond->count > 0) { 196 cond->count--; 197 } 198 (VOID)pthread_mutex_unlock(cond->mutex); 199} 200 201 202int pthread_cond_broadcast(pthread_cond_t *cond) 203{ 204 int ret = 0; 205 206 if (cond == NULL) { 207 return EINVAL; 208 } 209 210 (VOID)pthread_mutex_lock(cond->mutex); 211 if (cond->count > 0) { 212 cond->count = 0; 213 (VOID)pthread_mutex_unlock(cond->mutex); 214 (VOID)LOS_EventWrite(&(cond->event), BROADCAST_EVENT); 215 return ret; 216 } 217 (VOID)pthread_mutex_unlock(cond->mutex); 218 219 return ret; 220} 221 222int pthread_cond_signal(pthread_cond_t *cond) 223{ 224 int ret = 0; 225 226 if (cond == NULL) { 227 return EINVAL; 228 } 229 230 (VOID)pthread_mutex_lock(cond->mutex); 231 if (cond->count > 0) { 232 cond->count--; 233 (VOID)pthread_mutex_unlock(cond->mutex); 234 // This should modify to once. 235 (VOID)LOS_EventWrite(&(cond->event), BROADCAST_EVENT); 236 237 return ret; 238 } 239 (VOID)pthread_mutex_unlock(cond->mutex); 240 241 return ret; 242} 243 244STATIC INT32 ProcessReturnVal(pthread_cond_t *cond, INT32 val) 245{ 246 INT32 ret; 247 switch (val) { 248 /* 0: event does not occur */ 249 case 0: 250 case BROADCAST_EVENT: 251 ret = 0; 252 break; 253 case LOS_ERRNO_EVENT_READ_TIMEOUT: 254 PthreadCountSub(cond); 255 ret = ETIMEDOUT; 256 break; 257 default: 258 PthreadCountSub(cond); 259 ret = EINVAL; 260 break; 261 } 262 263 return ret; 264} 265 266int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 267 const struct timespec *ts) 268{ 269 INT32 ret; 270 UINT64 absTicks; 271 LosMuxCB *muxPosted = NULL; 272 pthread_testcancel(); 273 if ((cond == NULL) || (mutex == NULL) || (ts == NULL) || (mutex->magic != _MUX_MAGIC)) { 274 return EINVAL; 275 } 276 277 muxPosted = GET_MUX(mutex->handle); 278 if ((mutex->stAttr.type == PTHREAD_MUTEX_ERRORCHECK) && (g_losTask.runTask != muxPosted->owner)) { 279 return EPERM; 280 } 281 282 if (CondInitCheck(cond)) { 283 ret = pthread_cond_init(cond, NULL); 284 if (ret != 0) { 285 return ret; 286 } 287 } 288 289 (VOID)pthread_mutex_lock(cond->mutex); 290 cond->count++; 291 (VOID)pthread_mutex_unlock(cond->mutex); 292 293 ret = OsGetTickTimeFromNow(ts, cond->clock, &absTicks); 294 if (ret != 0) { 295 return ret; 296 } 297 298 if (absTicks >= UINT32_MAX) { 299 return EINVAL; 300 } 301 302 if (pthread_mutex_unlock(mutex) != 0) { 303 PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__); 304 } 305 306 ret = (INT32)LOS_EventRead(&(cond->event), 0x0f, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, (UINT32)absTicks); 307 308 if (pthread_mutex_lock(mutex) != 0) { 309 PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__); 310 } 311 312 ret = ProcessReturnVal(cond, ret); 313 pthread_testcancel(); 314 315 return ret; 316} 317 318int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 319{ 320 int ret; 321 322 if ((cond == NULL) || (mutex == NULL)) { 323 return EINVAL; 324 } 325 326 if (CondInitCheck(cond)) { 327 ret = pthread_cond_init(cond, NULL); 328 if (ret != 0) { 329 return ret; 330 } 331 } 332 333 (VOID)pthread_mutex_lock(cond->mutex); 334 cond->count++; 335 (VOID)pthread_mutex_unlock(cond->mutex); 336 337 if (pthread_mutex_unlock(mutex) != 0) { 338 PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__); 339 } 340 ret = (INT32)LOS_EventRead(&(cond->event), 0x0f, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); 341 if (pthread_mutex_lock(mutex) != 0) { 342 PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__); 343 } 344 345 switch (ret) { 346 /* 0: event does not occur */ 347 case 0: 348 case BROADCAST_EVENT: 349 ret = 0; 350 break; 351 default: 352 PthreadCountSub(cond); 353 ret = EINVAL; 354 break; 355 } 356 357 return ret; 358} 359