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