xref: /kernel/liteos_m/kal/posix/src/pthread_cond.c (revision 3d8536b4)
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