10d163575Sopenharmony_ci/* 20d163575Sopenharmony_ci * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. 30d163575Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. 40d163575Sopenharmony_ci * 50d163575Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 60d163575Sopenharmony_ci * are permitted provided that the following conditions are met: 70d163575Sopenharmony_ci * 80d163575Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, this list of 90d163575Sopenharmony_ci * conditions and the following disclaimer. 100d163575Sopenharmony_ci * 110d163575Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, this list 120d163575Sopenharmony_ci * of conditions and the following disclaimer in the documentation and/or other materials 130d163575Sopenharmony_ci * provided with the distribution. 140d163575Sopenharmony_ci * 150d163575Sopenharmony_ci * 3. Neither the name of the copyright holder nor the names of its contributors may be used 160d163575Sopenharmony_ci * to endorse or promote products derived from this software without specific prior written 170d163575Sopenharmony_ci * permission. 180d163575Sopenharmony_ci * 190d163575Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 200d163575Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 210d163575Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 220d163575Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 230d163575Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 240d163575Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 250d163575Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 260d163575Sopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 270d163575Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 280d163575Sopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 290d163575Sopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 300d163575Sopenharmony_ci */ 310d163575Sopenharmony_ci 320d163575Sopenharmony_ci#include "pprivate.h" 330d163575Sopenharmony_ci#include "pthread.h" 340d163575Sopenharmony_ci#include "stdlib.h" 350d163575Sopenharmony_ci#include "time_posix.h" 360d163575Sopenharmony_ci#include "los_atomic.h" 370d163575Sopenharmony_ci#include "los_event_pri.h" 380d163575Sopenharmony_ci 390d163575Sopenharmony_ci 400d163575Sopenharmony_ci#define BROADCAST_EVENT 1 410d163575Sopenharmony_ci#define COND_COUNTER_STEP 0x0004U 420d163575Sopenharmony_ci#define COND_FLAGS_MASK 0x0003U 430d163575Sopenharmony_ci#define COND_COUNTER_MASK (~COND_FLAGS_MASK) 440d163575Sopenharmony_ci 450d163575Sopenharmony_ciSTATIC INLINE INT32 CondInitCheck(const pthread_cond_t *cond) 460d163575Sopenharmony_ci{ 470d163575Sopenharmony_ci if ((cond->event.stEventList.pstPrev == NULL) && 480d163575Sopenharmony_ci (cond->event.stEventList.pstNext == NULL)) { 490d163575Sopenharmony_ci return 1; 500d163575Sopenharmony_ci } 510d163575Sopenharmony_ci return 0; 520d163575Sopenharmony_ci} 530d163575Sopenharmony_ci 540d163575Sopenharmony_ciint pthread_condattr_getpshared(const pthread_condattr_t *attr, int *shared) 550d163575Sopenharmony_ci{ 560d163575Sopenharmony_ci if ((attr == NULL) || (shared == NULL)) { 570d163575Sopenharmony_ci return EINVAL; 580d163575Sopenharmony_ci } 590d163575Sopenharmony_ci 600d163575Sopenharmony_ci *shared = PTHREAD_PROCESS_PRIVATE; 610d163575Sopenharmony_ci 620d163575Sopenharmony_ci return 0; 630d163575Sopenharmony_ci} 640d163575Sopenharmony_ci 650d163575Sopenharmony_ciint pthread_condattr_setpshared(pthread_condattr_t *attr, int shared) 660d163575Sopenharmony_ci{ 670d163575Sopenharmony_ci (VOID)attr; 680d163575Sopenharmony_ci if ((shared != PTHREAD_PROCESS_PRIVATE) && (shared != PTHREAD_PROCESS_SHARED)) { 690d163575Sopenharmony_ci return EINVAL; 700d163575Sopenharmony_ci } 710d163575Sopenharmony_ci 720d163575Sopenharmony_ci if (shared != PTHREAD_PROCESS_PRIVATE) { 730d163575Sopenharmony_ci return ENOSYS; 740d163575Sopenharmony_ci } 750d163575Sopenharmony_ci 760d163575Sopenharmony_ci return 0; 770d163575Sopenharmony_ci} 780d163575Sopenharmony_ci 790d163575Sopenharmony_ciint pthread_condattr_destroy(pthread_condattr_t *attr) 800d163575Sopenharmony_ci{ 810d163575Sopenharmony_ci if (attr == NULL) { 820d163575Sopenharmony_ci return EINVAL; 830d163575Sopenharmony_ci } 840d163575Sopenharmony_ci 850d163575Sopenharmony_ci return 0; 860d163575Sopenharmony_ci} 870d163575Sopenharmony_ci 880d163575Sopenharmony_ciint pthread_condattr_init(pthread_condattr_t *attr) 890d163575Sopenharmony_ci{ 900d163575Sopenharmony_ci if (attr == NULL) { 910d163575Sopenharmony_ci return EINVAL; 920d163575Sopenharmony_ci } 930d163575Sopenharmony_ci 940d163575Sopenharmony_ci return 0; 950d163575Sopenharmony_ci} 960d163575Sopenharmony_ci 970d163575Sopenharmony_ciint pthread_cond_destroy(pthread_cond_t *cond) 980d163575Sopenharmony_ci{ 990d163575Sopenharmony_ci if (cond == NULL) { 1000d163575Sopenharmony_ci return EINVAL; 1010d163575Sopenharmony_ci } 1020d163575Sopenharmony_ci 1030d163575Sopenharmony_ci if (CondInitCheck(cond)) { 1040d163575Sopenharmony_ci return ENOERR; 1050d163575Sopenharmony_ci } 1060d163575Sopenharmony_ci 1070d163575Sopenharmony_ci if (LOS_EventDestroy(&cond->event) != LOS_OK) { 1080d163575Sopenharmony_ci return EBUSY; 1090d163575Sopenharmony_ci } 1100d163575Sopenharmony_ci if (pthread_mutex_destroy(cond->mutex) != ENOERR) { 1110d163575Sopenharmony_ci PRINT_ERR("%s mutex destroy fail!\n", __FUNCTION__); 1120d163575Sopenharmony_ci return EINVAL; 1130d163575Sopenharmony_ci } 1140d163575Sopenharmony_ci free(cond->mutex); 1150d163575Sopenharmony_ci cond->mutex = NULL; 1160d163575Sopenharmony_ci return ENOERR; 1170d163575Sopenharmony_ci} 1180d163575Sopenharmony_ci 1190d163575Sopenharmony_ciint pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) 1200d163575Sopenharmony_ci{ 1210d163575Sopenharmony_ci int ret = ENOERR; 1220d163575Sopenharmony_ci 1230d163575Sopenharmony_ci if (cond == NULL) { 1240d163575Sopenharmony_ci return EINVAL; 1250d163575Sopenharmony_ci } 1260d163575Sopenharmony_ci (VOID)attr; 1270d163575Sopenharmony_ci (VOID)LOS_EventInit(&(cond->event)); 1280d163575Sopenharmony_ci 1290d163575Sopenharmony_ci cond->mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); 1300d163575Sopenharmony_ci if (cond->mutex == NULL) { 1310d163575Sopenharmony_ci return ENOMEM; 1320d163575Sopenharmony_ci } 1330d163575Sopenharmony_ci 1340d163575Sopenharmony_ci (VOID)pthread_mutex_init(cond->mutex, NULL); 1350d163575Sopenharmony_ci 1360d163575Sopenharmony_ci cond->value = 0; 1370d163575Sopenharmony_ci (VOID)pthread_mutex_lock(cond->mutex); 1380d163575Sopenharmony_ci cond->count = 0; 1390d163575Sopenharmony_ci (VOID)pthread_mutex_unlock(cond->mutex); 1400d163575Sopenharmony_ci 1410d163575Sopenharmony_ci return ret; 1420d163575Sopenharmony_ci} 1430d163575Sopenharmony_ci 1440d163575Sopenharmony_ciSTATIC VOID PthreadCondValueModify(pthread_cond_t *cond) 1450d163575Sopenharmony_ci{ 1460d163575Sopenharmony_ci UINT32 flags = ((UINT32)cond->value & COND_FLAGS_MASK); 1470d163575Sopenharmony_ci INT32 oldVal, newVal; 1480d163575Sopenharmony_ci 1490d163575Sopenharmony_ci while (true) { 1500d163575Sopenharmony_ci oldVal = cond->value; 1510d163575Sopenharmony_ci newVal = (INT32)(((UINT32)(oldVal - COND_COUNTER_STEP) & COND_COUNTER_MASK) | flags); 1520d163575Sopenharmony_ci if (LOS_AtomicCmpXchg32bits(&cond->value, newVal, oldVal) == 0) { 1530d163575Sopenharmony_ci break; 1540d163575Sopenharmony_ci } 1550d163575Sopenharmony_ci } 1560d163575Sopenharmony_ci} 1570d163575Sopenharmony_ci 1580d163575Sopenharmony_ciint pthread_cond_broadcast(pthread_cond_t *cond) 1590d163575Sopenharmony_ci{ 1600d163575Sopenharmony_ci int ret = ENOERR; 1610d163575Sopenharmony_ci 1620d163575Sopenharmony_ci if (cond == NULL) { 1630d163575Sopenharmony_ci return EINVAL; 1640d163575Sopenharmony_ci } 1650d163575Sopenharmony_ci 1660d163575Sopenharmony_ci (VOID)pthread_mutex_lock(cond->mutex); 1670d163575Sopenharmony_ci if (cond->count > 0) { 1680d163575Sopenharmony_ci cond->count = 0; 1690d163575Sopenharmony_ci (VOID)pthread_mutex_unlock(cond->mutex); 1700d163575Sopenharmony_ci 1710d163575Sopenharmony_ci PthreadCondValueModify(cond); 1720d163575Sopenharmony_ci 1730d163575Sopenharmony_ci (VOID)LOS_EventWrite(&(cond->event), BROADCAST_EVENT); 1740d163575Sopenharmony_ci return ret; 1750d163575Sopenharmony_ci } 1760d163575Sopenharmony_ci (VOID)pthread_mutex_unlock(cond->mutex); 1770d163575Sopenharmony_ci 1780d163575Sopenharmony_ci return ret; 1790d163575Sopenharmony_ci} 1800d163575Sopenharmony_ci 1810d163575Sopenharmony_ciint pthread_cond_signal(pthread_cond_t *cond) 1820d163575Sopenharmony_ci{ 1830d163575Sopenharmony_ci int ret = ENOERR; 1840d163575Sopenharmony_ci 1850d163575Sopenharmony_ci if (cond == NULL) { 1860d163575Sopenharmony_ci return EINVAL; 1870d163575Sopenharmony_ci } 1880d163575Sopenharmony_ci 1890d163575Sopenharmony_ci (VOID)pthread_mutex_lock(cond->mutex); 1900d163575Sopenharmony_ci if (cond->count > 0) { 1910d163575Sopenharmony_ci cond->count--; 1920d163575Sopenharmony_ci (VOID)pthread_mutex_unlock(cond->mutex); 1930d163575Sopenharmony_ci PthreadCondValueModify(cond); 1940d163575Sopenharmony_ci (VOID)OsEventWriteOnce(&(cond->event), 0x01); 1950d163575Sopenharmony_ci 1960d163575Sopenharmony_ci return ret; 1970d163575Sopenharmony_ci } 1980d163575Sopenharmony_ci (VOID)pthread_mutex_unlock(cond->mutex); 1990d163575Sopenharmony_ci 2000d163575Sopenharmony_ci return ret; 2010d163575Sopenharmony_ci} 2020d163575Sopenharmony_ci 2030d163575Sopenharmony_ciSTATIC INT32 PthreadCondWaitSub(pthread_cond_t *cond, INT32 value, UINT32 ticks) 2040d163575Sopenharmony_ci{ 2050d163575Sopenharmony_ci EventCond eventCond = { &cond->value, value, ~0x01U }; 2060d163575Sopenharmony_ci /* 2070d163575Sopenharmony_ci * When the scheduling lock is held: 2080d163575Sopenharmony_ci * (1) value is not equal to cond->value, clear the event message and 2090d163575Sopenharmony_ci * do not block the current thread, because other threads is calling pthread_cond_broadcast or 2100d163575Sopenharmony_ci * pthread_cond_signal to modify cond->value and wake up the current thread, 2110d163575Sopenharmony_ci * and others threads will block on the scheduling lock until the current thread releases 2120d163575Sopenharmony_ci * the scheduling lock. 2130d163575Sopenharmony_ci * (2) value is equal to cond->value, block the current thread 2140d163575Sopenharmony_ci * and wait to be awakened by other threads. 2150d163575Sopenharmony_ci */ 2160d163575Sopenharmony_ci return (int)OsEventReadWithCond(&eventCond, &(cond->event), 0x0fU, 2170d163575Sopenharmony_ci LOS_WAITMODE_OR | LOS_WAITMODE_CLR, ticks); 2180d163575Sopenharmony_ci} 2190d163575Sopenharmony_ciSTATIC VOID PthreadCountSub(pthread_cond_t *cond) 2200d163575Sopenharmony_ci{ 2210d163575Sopenharmony_ci (VOID)pthread_mutex_lock(cond->mutex); 2220d163575Sopenharmony_ci if (cond->count > 0) { 2230d163575Sopenharmony_ci cond->count--; 2240d163575Sopenharmony_ci } 2250d163575Sopenharmony_ci (VOID)pthread_mutex_unlock(cond->mutex); 2260d163575Sopenharmony_ci} 2270d163575Sopenharmony_ci 2280d163575Sopenharmony_ciSTATIC INT32 ProcessReturnVal(pthread_cond_t *cond, INT32 val) 2290d163575Sopenharmony_ci{ 2300d163575Sopenharmony_ci INT32 ret; 2310d163575Sopenharmony_ci switch (val) { 2320d163575Sopenharmony_ci /* 0: event does not occur */ 2330d163575Sopenharmony_ci case 0: 2340d163575Sopenharmony_ci case BROADCAST_EVENT: 2350d163575Sopenharmony_ci ret = ENOERR; 2360d163575Sopenharmony_ci break; 2370d163575Sopenharmony_ci case LOS_ERRNO_EVENT_READ_TIMEOUT: 2380d163575Sopenharmony_ci PthreadCountSub(cond); 2390d163575Sopenharmony_ci ret = ETIMEDOUT; 2400d163575Sopenharmony_ci break; 2410d163575Sopenharmony_ci default: 2420d163575Sopenharmony_ci PthreadCountSub(cond); 2430d163575Sopenharmony_ci ret = EINVAL; 2440d163575Sopenharmony_ci break; 2450d163575Sopenharmony_ci } 2460d163575Sopenharmony_ci return ret; 2470d163575Sopenharmony_ci} 2480d163575Sopenharmony_ci 2490d163575Sopenharmony_ciint pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 2500d163575Sopenharmony_ci const struct timespec *absTime) 2510d163575Sopenharmony_ci{ 2520d163575Sopenharmony_ci UINT32 absTicks; 2530d163575Sopenharmony_ci INT32 ret; 2540d163575Sopenharmony_ci INT32 oldValue; 2550d163575Sopenharmony_ci 2560d163575Sopenharmony_ci pthread_testcancel(); 2570d163575Sopenharmony_ci if ((cond == NULL) || (mutex == NULL) || (absTime == NULL)) { 2580d163575Sopenharmony_ci return EINVAL; 2590d163575Sopenharmony_ci } 2600d163575Sopenharmony_ci 2610d163575Sopenharmony_ci if (CondInitCheck(cond)) { 2620d163575Sopenharmony_ci ret = pthread_cond_init(cond, NULL); 2630d163575Sopenharmony_ci if (ret != ENOERR) { 2640d163575Sopenharmony_ci return ret; 2650d163575Sopenharmony_ci } 2660d163575Sopenharmony_ci } 2670d163575Sopenharmony_ci oldValue = cond->value; 2680d163575Sopenharmony_ci 2690d163575Sopenharmony_ci (VOID)pthread_mutex_lock(cond->mutex); 2700d163575Sopenharmony_ci cond->count++; 2710d163575Sopenharmony_ci (VOID)pthread_mutex_unlock(cond->mutex); 2720d163575Sopenharmony_ci 2730d163575Sopenharmony_ci if ((absTime->tv_sec == 0) && (absTime->tv_nsec == 0)) { 2740d163575Sopenharmony_ci return ETIMEDOUT; 2750d163575Sopenharmony_ci } 2760d163575Sopenharmony_ci 2770d163575Sopenharmony_ci if (!ValidTimeSpec(absTime)) { 2780d163575Sopenharmony_ci return EINVAL; 2790d163575Sopenharmony_ci } 2800d163575Sopenharmony_ci 2810d163575Sopenharmony_ci absTicks = OsTimeSpec2Tick(absTime); 2820d163575Sopenharmony_ci if (pthread_mutex_unlock(mutex) != ENOERR) { 2830d163575Sopenharmony_ci PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__); 2840d163575Sopenharmony_ci } 2850d163575Sopenharmony_ci 2860d163575Sopenharmony_ci#ifndef LOSCFG_ARCH_CORTEX_M7 2870d163575Sopenharmony_ci ret = PthreadCondWaitSub(cond, oldValue, absTicks); 2880d163575Sopenharmony_ci#else 2890d163575Sopenharmony_ci ret = (INT32)LOS_EventRead(&(cond->event), 0x0f, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, absTicks); 2900d163575Sopenharmony_ci#endif 2910d163575Sopenharmony_ci if (pthread_mutex_lock(mutex) != ENOERR) { 2920d163575Sopenharmony_ci PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__); 2930d163575Sopenharmony_ci } 2940d163575Sopenharmony_ci 2950d163575Sopenharmony_ci ret = ProcessReturnVal(cond, ret); 2960d163575Sopenharmony_ci pthread_testcancel(); 2970d163575Sopenharmony_ci return ret; 2980d163575Sopenharmony_ci} 2990d163575Sopenharmony_ci 3000d163575Sopenharmony_ciint pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 3010d163575Sopenharmony_ci{ 3020d163575Sopenharmony_ci int ret; 3030d163575Sopenharmony_ci int oldValue; 3040d163575Sopenharmony_ci 3050d163575Sopenharmony_ci if ((cond == NULL) || (mutex == NULL)) { 3060d163575Sopenharmony_ci return EINVAL; 3070d163575Sopenharmony_ci } 3080d163575Sopenharmony_ci 3090d163575Sopenharmony_ci if (CondInitCheck(cond)) { 3100d163575Sopenharmony_ci ret = pthread_cond_init(cond, NULL); 3110d163575Sopenharmony_ci if (ret != ENOERR) { 3120d163575Sopenharmony_ci return ret; 3130d163575Sopenharmony_ci } 3140d163575Sopenharmony_ci } 3150d163575Sopenharmony_ci oldValue = cond->value; 3160d163575Sopenharmony_ci 3170d163575Sopenharmony_ci (VOID)pthread_mutex_lock(cond->mutex); 3180d163575Sopenharmony_ci cond->count++; 3190d163575Sopenharmony_ci (VOID)pthread_mutex_unlock(cond->mutex); 3200d163575Sopenharmony_ci 3210d163575Sopenharmony_ci if (pthread_mutex_unlock(mutex) != ENOERR) { 3220d163575Sopenharmony_ci PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__); 3230d163575Sopenharmony_ci } 3240d163575Sopenharmony_ci 3250d163575Sopenharmony_ci#ifndef LOSCFG_ARCH_CORTEX_M7 3260d163575Sopenharmony_ci ret = PthreadCondWaitSub(cond, oldValue, LOS_WAIT_FOREVER); 3270d163575Sopenharmony_ci#else 3280d163575Sopenharmony_ci ret = (INT32)LOS_EventRead(&(cond->event), 0x0f, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); 3290d163575Sopenharmony_ci#endif 3300d163575Sopenharmony_ci if (pthread_mutex_lock(mutex) != ENOERR) { 3310d163575Sopenharmony_ci PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__); 3320d163575Sopenharmony_ci } 3330d163575Sopenharmony_ci 3340d163575Sopenharmony_ci switch (ret) { 3350d163575Sopenharmony_ci /* 0: event does not occur */ 3360d163575Sopenharmony_ci case 0: 3370d163575Sopenharmony_ci case BROADCAST_EVENT: 3380d163575Sopenharmony_ci ret = ENOERR; 3390d163575Sopenharmony_ci break; 3400d163575Sopenharmony_ci default: 3410d163575Sopenharmony_ci PthreadCountSub(cond); 3420d163575Sopenharmony_ci ret = EINVAL; 3430d163575Sopenharmony_ci break; 3440d163575Sopenharmony_ci } 3450d163575Sopenharmony_ci 3460d163575Sopenharmony_ci return ret; 3470d163575Sopenharmony_ci} 3480d163575Sopenharmony_ci 349