• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "pprivate.h"
33 #include "pthread.h"
34 #include "stdlib.h"
35 #include "time_posix.h"
36 #include "los_atomic.h"
37 #include "los_event_pri.h"
38 
39 
40 #define BROADCAST_EVENT     1
41 #define COND_COUNTER_STEP   0x0004U
42 #define COND_FLAGS_MASK     0x0003U
43 #define COND_COUNTER_MASK   (~COND_FLAGS_MASK)
44 
CondInitCheck(const pthread_cond_t * cond)45 STATIC INLINE INT32 CondInitCheck(const pthread_cond_t *cond)
46 {
47     if ((cond->event.stEventList.pstPrev == NULL) &&
48         (cond->event.stEventList.pstNext == NULL)) {
49         return 1;
50     }
51     return 0;
52 }
53 
pthread_condattr_getpshared(const pthread_condattr_t * attr,int * shared)54 int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *shared)
55 {
56     if ((attr == NULL) || (shared == NULL)) {
57         return EINVAL;
58     }
59 
60     *shared = PTHREAD_PROCESS_PRIVATE;
61 
62     return 0;
63 }
64 
pthread_condattr_setpshared(pthread_condattr_t * attr,int shared)65 int pthread_condattr_setpshared(pthread_condattr_t *attr, int shared)
66 {
67     (VOID)attr;
68     if ((shared != PTHREAD_PROCESS_PRIVATE) && (shared != PTHREAD_PROCESS_SHARED)) {
69         return EINVAL;
70     }
71 
72     if (shared != PTHREAD_PROCESS_PRIVATE) {
73         return ENOSYS;
74     }
75 
76     return 0;
77 }
78 
pthread_condattr_destroy(pthread_condattr_t * attr)79 int pthread_condattr_destroy(pthread_condattr_t *attr)
80 {
81     if (attr == NULL) {
82         return EINVAL;
83     }
84 
85     return 0;
86 }
87 
pthread_condattr_init(pthread_condattr_t * attr)88 int pthread_condattr_init(pthread_condattr_t *attr)
89 {
90     if (attr == NULL) {
91         return EINVAL;
92     }
93 
94     return 0;
95 }
96 
pthread_cond_destroy(pthread_cond_t * cond)97 int pthread_cond_destroy(pthread_cond_t *cond)
98 {
99     if (cond == NULL) {
100         return EINVAL;
101     }
102 
103     if (CondInitCheck(cond)) {
104         return ENOERR;
105     }
106 
107     if (LOS_EventDestroy(&cond->event) != LOS_OK) {
108         return EBUSY;
109     }
110     if (pthread_mutex_destroy(cond->mutex) != ENOERR) {
111         PRINT_ERR("%s mutex destroy fail!\n", __FUNCTION__);
112         return EINVAL;
113     }
114     free(cond->mutex);
115     cond->mutex = NULL;
116     return ENOERR;
117 }
118 
pthread_cond_init(pthread_cond_t * cond,const pthread_condattr_t * attr)119 int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
120 {
121     int ret = ENOERR;
122 
123     if (cond == NULL) {
124         return EINVAL;
125     }
126     (VOID)attr;
127     (VOID)LOS_EventInit(&(cond->event));
128 
129     cond->mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
130     if (cond->mutex == NULL) {
131         return ENOMEM;
132     }
133 
134     (VOID)pthread_mutex_init(cond->mutex, NULL);
135 
136     cond->value = 0;
137     (VOID)pthread_mutex_lock(cond->mutex);
138     cond->count = 0;
139     (VOID)pthread_mutex_unlock(cond->mutex);
140 
141     return ret;
142 }
143 
PthreadCondValueModify(pthread_cond_t * cond)144 STATIC VOID PthreadCondValueModify(pthread_cond_t *cond)
145 {
146     UINT32 flags = ((UINT32)cond->value & COND_FLAGS_MASK);
147     INT32 oldVal, newVal;
148 
149     while (true) {
150         oldVal = cond->value;
151         newVal = (INT32)(((UINT32)(oldVal - COND_COUNTER_STEP) & COND_COUNTER_MASK) | flags);
152         if (LOS_AtomicCmpXchg32bits(&cond->value, newVal, oldVal) == 0) {
153             break;
154         }
155     }
156 }
157 
pthread_cond_broadcast(pthread_cond_t * cond)158 int pthread_cond_broadcast(pthread_cond_t *cond)
159 {
160     int ret = ENOERR;
161 
162     if (cond == NULL) {
163         return EINVAL;
164     }
165 
166     (VOID)pthread_mutex_lock(cond->mutex);
167     if (cond->count > 0) {
168         cond->count = 0;
169         (VOID)pthread_mutex_unlock(cond->mutex);
170 
171         PthreadCondValueModify(cond);
172 
173         (VOID)LOS_EventWrite(&(cond->event), BROADCAST_EVENT);
174         return ret;
175     }
176     (VOID)pthread_mutex_unlock(cond->mutex);
177 
178     return ret;
179 }
180 
pthread_cond_signal(pthread_cond_t * cond)181 int pthread_cond_signal(pthread_cond_t *cond)
182 {
183     int ret = ENOERR;
184 
185     if (cond == NULL) {
186         return EINVAL;
187     }
188 
189     (VOID)pthread_mutex_lock(cond->mutex);
190     if (cond->count > 0) {
191         cond->count--;
192         (VOID)pthread_mutex_unlock(cond->mutex);
193         PthreadCondValueModify(cond);
194         (VOID)OsEventWriteOnce(&(cond->event), 0x01);
195 
196         return ret;
197     }
198     (VOID)pthread_mutex_unlock(cond->mutex);
199 
200     return ret;
201 }
202 
PthreadCondWaitSub(pthread_cond_t * cond,INT32 value,UINT32 ticks)203 STATIC INT32 PthreadCondWaitSub(pthread_cond_t *cond, INT32 value, UINT32 ticks)
204 {
205     EventCond eventCond = { &cond->value, value, ~0x01U };
206     /*
207      * When the scheduling lock is held:
208      * (1) value is not equal to cond->value, clear the event message and
209      * do not block the current thread, because other threads is calling pthread_cond_broadcast or
210      * pthread_cond_signal to modify cond->value and wake up the current thread,
211      * and others threads will block on the scheduling lock until the current thread releases
212      * the scheduling lock.
213      * (2) value is equal to cond->value, block the current thread
214      * and wait to be awakened by other threads.
215      */
216     return (int)OsEventReadWithCond(&eventCond, &(cond->event), 0x0fU,
217                                     LOS_WAITMODE_OR | LOS_WAITMODE_CLR, ticks);
218 }
PthreadCountSub(pthread_cond_t * cond)219 STATIC VOID PthreadCountSub(pthread_cond_t *cond)
220 {
221     (VOID)pthread_mutex_lock(cond->mutex);
222     if (cond->count > 0) {
223         cond->count--;
224     }
225     (VOID)pthread_mutex_unlock(cond->mutex);
226 }
227 
ProcessReturnVal(pthread_cond_t * cond,INT32 val)228 STATIC INT32 ProcessReturnVal(pthread_cond_t *cond, INT32 val)
229 {
230     INT32 ret;
231     switch (val) {
232         /* 0: event does not occur */
233         case 0:
234         case BROADCAST_EVENT:
235             ret = ENOERR;
236             break;
237         case LOS_ERRNO_EVENT_READ_TIMEOUT:
238             PthreadCountSub(cond);
239             ret = ETIMEDOUT;
240             break;
241         default:
242             PthreadCountSub(cond);
243             ret = EINVAL;
244             break;
245     }
246     return ret;
247 }
248 
pthread_cond_timedwait(pthread_cond_t * cond,pthread_mutex_t * mutex,const struct timespec * absTime)249 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
250                            const struct timespec *absTime)
251 {
252     UINT32 absTicks;
253     INT32 ret;
254     INT32 oldValue;
255 
256     pthread_testcancel();
257     if ((cond == NULL) || (mutex == NULL) || (absTime == NULL)) {
258         return EINVAL;
259     }
260 
261     if (CondInitCheck(cond)) {
262         ret = pthread_cond_init(cond, NULL);
263         if (ret != ENOERR) {
264             return ret;
265         }
266     }
267     oldValue = cond->value;
268 
269     (VOID)pthread_mutex_lock(cond->mutex);
270     cond->count++;
271     (VOID)pthread_mutex_unlock(cond->mutex);
272 
273     if ((absTime->tv_sec == 0) && (absTime->tv_nsec == 0)) {
274         return ETIMEDOUT;
275     }
276 
277     if (!ValidTimeSpec(absTime)) {
278         return EINVAL;
279     }
280 
281     absTicks = OsTimeSpec2Tick(absTime);
282     if (pthread_mutex_unlock(mutex) != ENOERR) {
283         PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
284     }
285 
286 #ifndef LOSCFG_ARCH_CORTEX_M7
287     ret = PthreadCondWaitSub(cond, oldValue, absTicks);
288 #else
289     ret = (INT32)LOS_EventRead(&(cond->event), 0x0f, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, absTicks);
290 #endif
291     if (pthread_mutex_lock(mutex) != ENOERR) {
292         PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
293     }
294 
295     ret = ProcessReturnVal(cond, ret);
296     pthread_testcancel();
297     return ret;
298 }
299 
pthread_cond_wait(pthread_cond_t * cond,pthread_mutex_t * mutex)300 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
301 {
302     int ret;
303     int oldValue;
304 
305     if ((cond == NULL) || (mutex == NULL)) {
306         return EINVAL;
307     }
308 
309     if (CondInitCheck(cond)) {
310         ret = pthread_cond_init(cond, NULL);
311         if (ret != ENOERR) {
312             return ret;
313         }
314     }
315     oldValue = cond->value;
316 
317     (VOID)pthread_mutex_lock(cond->mutex);
318     cond->count++;
319     (VOID)pthread_mutex_unlock(cond->mutex);
320 
321     if (pthread_mutex_unlock(mutex) != ENOERR) {
322         PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
323     }
324 
325 #ifndef LOSCFG_ARCH_CORTEX_M7
326     ret = PthreadCondWaitSub(cond, oldValue, LOS_WAIT_FOREVER);
327 #else
328     ret = (INT32)LOS_EventRead(&(cond->event), 0x0f, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
329 #endif
330     if (pthread_mutex_lock(mutex) != ENOERR) {
331         PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
332     }
333 
334     switch (ret) {
335         /* 0: event does not occur */
336         case 0:
337         case BROADCAST_EVENT:
338             ret = ENOERR;
339             break;
340         default:
341             PthreadCountSub(cond);
342             ret = EINVAL;
343             break;
344     }
345 
346     return ret;
347 }
348 
349