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