1 /*
2  * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3  */
4 
5 #include <stdint.h>
6 #include <string.h>
7 #include <errno.h>
8 #include <time.h>
9 #include <pthread.h>
10 #include <aos/kernel.h>
11 
12 #include "internal/pthread.h"
13 
pthread_cond_init(pthread_cond_t * cond,const pthread_condattr_t * attr)14 int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
15 {
16     int ret = 0;
17 
18     if (cond == NULL) {
19         return EINVAL;
20     }
21 
22     memset(cond, 0, sizeof(pthread_cond_t));
23     ret = aos_mutex_new((aos_mutex_t*)(&(cond->lock)));
24     if (ret != 0) {
25         return EAGAIN;
26     }
27 
28     ret = aos_sem_new((aos_sem_t*)(&(cond->wait_sem)), 0);
29     if (ret != 0) {
30         aos_mutex_free((aos_mutex_t*)(&(cond->lock)));
31         return EAGAIN;
32     }
33 
34     ret = aos_sem_new((aos_sem_t*)(&(cond->wait_done)), 0);
35     if (ret != 0) {
36         aos_mutex_free((aos_mutex_t*)(&(cond->lock)));
37         aos_sem_free((aos_sem_t*)(&(cond->wait_sem)));
38         return EAGAIN;
39     }
40 
41     cond->waiting = cond->signals = 0;
42     cond->flag = PTHREAD_DYN_INIT;
43 
44     if (attr != NULL) {
45         cond->attr = *attr;
46     }
47 
48     return 0;
49 }
50 
pthread_cond_destroy(pthread_cond_t * cond)51 int pthread_cond_destroy(pthread_cond_t *cond)
52 {
53     if (cond == NULL) {
54         return EINVAL;
55     }
56 
57     aos_mutex_free((aos_mutex_t*)(&(cond->lock)));
58     aos_sem_free((aos_sem_t*)(&(cond->wait_sem)));
59     aos_sem_free((aos_sem_t*)(&(cond->wait_done)));
60 
61     return 0;
62 }
63 
pthread_cond_broadcast(pthread_cond_t * cond)64 int pthread_cond_broadcast(pthread_cond_t *cond)
65 {
66     int i           = 0;
67     int num_waiting = 0;
68 
69     if (cond == NULL)
70         return EINVAL;
71 
72     if (cond->flag != PTHREAD_DYN_INIT)
73         return 0;
74 
75     /* If there are waiting threads not already signalled, then
76      * signal the condition and wait for the thread to respond.
77      */
78     aos_mutex_lock((aos_mutex_t*)(&(cond->lock)), AOS_WAIT_FOREVER);
79 
80     if (cond->waiting > cond->signals) {
81         num_waiting = (cond->waiting - cond->signals);
82         cond->signals = cond->waiting;
83 
84         for (i = 0; i < num_waiting; ++i) {
85             aos_sem_signal((aos_sem_t*)(&(cond->wait_sem)));
86         }
87         /* Now all released threads are blocked here, waiting for us.
88          * Collect them all (and win fabulous prizes!) :-)
89          */
90         aos_mutex_unlock((aos_mutex_t*)(&(cond->lock)));
91         for (i = 0; i < num_waiting; ++i) {
92             aos_sem_wait((aos_sem_t*)(&(cond->wait_done)), AOS_WAIT_FOREVER);
93         }
94     } else {
95         aos_mutex_unlock((aos_mutex_t*)(&(cond->lock)));
96     }
97 
98     return 0;
99 }
100 
pthread_cond_signal(pthread_cond_t * cond)101 int pthread_cond_signal(pthread_cond_t *cond)
102 {
103     if (cond == NULL)
104         return EINVAL;
105 
106     if (cond->flag != PTHREAD_DYN_INIT)
107         return 0;
108 
109     /* If there are waiting threads not already signalled, then
110      * signal the condition and wait for the thread to respond.
111      */
112     aos_mutex_lock((aos_mutex_t*)(&(cond->lock)), AOS_WAIT_FOREVER);
113     if ( cond->waiting > cond->signals ) {
114         (cond->signals)++;
115         aos_sem_signal((aos_sem_t*)(&(cond->wait_sem)));
116         aos_mutex_unlock((aos_mutex_t*)(&(cond->lock)));
117         aos_sem_wait((aos_sem_t*)(&(cond->wait_done)), AOS_WAIT_FOREVER);
118     } else {
119         aos_mutex_unlock((aos_mutex_t*)(&(cond->lock)));
120     }
121 
122     return 0;
123 }
124 
pthread_cond_timedwait_ms(pthread_cond_t * cond,pthread_mutex_t * mutex,int64_t ms)125 static int pthread_cond_timedwait_ms(pthread_cond_t *cond, pthread_mutex_t *mutex, int64_t ms)
126 {
127     int ret = 0;
128 
129     if (cond->flag == PTHREAD_STATIC_INIT) {
130         /* The cond is inited by PTHREAD_COND_INITIALIZER*/
131         ret = pthread_cond_init(cond, NULL);
132         if (ret != 0)
133             return ret;
134     }
135 
136     /* Obtain the protection mutex, and increment the number of waiters.
137      * This allows the signal mechanism to only perform a signal if there
138      * are waiting threads.
139      */
140     aos_mutex_lock((aos_mutex_t*)(&(cond->lock)), AOS_WAIT_FOREVER);
141     (cond->waiting)++;
142     aos_mutex_unlock((aos_mutex_t*)(&(cond->lock)));
143 
144     /* Unlock the mutex, as is required by condition variable semantics */
145     aos_mutex_unlock((aos_mutex_t*)(&(mutex->mutex)));
146 
147     /* Wait for a signal */
148     ret = aos_sem_wait((aos_sem_t*)(&(cond->wait_sem)), ms);
149 
150     /* Let the signaler know we have completed the wait, otherwise
151      * the signaler can race ahead and get the condition semaphore
152      * if we are stopped between the mutex unlock and semaphore wait,
153      * giving a deadlock.
154      */
155     aos_mutex_lock((aos_mutex_t*)(&(cond->lock)), AOS_WAIT_FOREVER);
156 
157     if (ret == -ETIMEDOUT) {
158         ret = ETIMEDOUT;
159     }
160 
161     if (cond->signals > 0) {
162         /* If we timed out, we need to eat a condition signal */
163         if (ret == ETIMEDOUT) {
164             aos_sem_wait((aos_sem_t*)(&(cond->wait_sem)), AOS_NO_WAIT);
165         }
166         /* We always notify the signal thread that we are done */
167         aos_sem_signal((aos_sem_t*)(&(cond->wait_done)));
168 
169         /* Signal handshake complete */
170         (cond->signals)--;
171     }
172 
173     (cond->waiting)--;
174 
175     aos_mutex_unlock((aos_mutex_t*)(&(cond->lock)));
176 
177     /* Lock the mutex, as is required by condition variable semantics */
178     aos_mutex_lock((aos_mutex_t*)(&(mutex->mutex)), AOS_WAIT_FOREVER);
179 
180     return ret;
181 }
182 
183 
pthread_cond_timedwait(pthread_cond_t * cond,pthread_mutex_t * mutex,const struct timespec * abstime)184 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
185                            const struct timespec *abstime)
186 {
187     int ret;
188     struct timeval now_tv = {0};
189     struct timespec now_tp = {0};
190     int64_t timeout_ms = 0;
191 
192     if ((cond == NULL) || (mutex == NULL)) {
193         return EINVAL;
194     }
195 
196     if (abstime == NULL) {
197         timeout_ms = AOS_WAIT_FOREVER;
198     } else {
199         if (cond->attr.clock == CLOCK_MONOTONIC) {
200             ret = clock_gettime(CLOCK_MONOTONIC, &now_tp);
201             if (ret != 0) {
202                 return EINVAL;
203             }
204 
205             timeout_ms = (abstime->tv_sec - now_tp.tv_sec) * 1000 +
206                          ((abstime->tv_nsec - now_tp.tv_nsec) / 1000000);
207         } else {
208             /* CLOCK_REALTIME */
209             gettimeofday(&now_tv, NULL);
210             timeout_ms = (abstime->tv_sec - now_tv.tv_sec) * 1000 +
211                          ((abstime->tv_nsec - now_tv.tv_usec * 1000) / 1000000);
212         }
213 
214         if (timeout_ms <= 0) {
215             /* The absolute time has already passed. Do not need to wait. */
216             return ETIMEDOUT;
217         }
218     }
219 
220     return pthread_cond_timedwait_ms(cond, mutex, timeout_ms);
221 }
222 
pthread_cond_timedwait_relative_np(pthread_cond_t * cond,pthread_mutex_t * mutex,const struct timespec * reltime)223 int pthread_cond_timedwait_relative_np(pthread_cond_t *cond, pthread_mutex_t *mutex,
224                                                 const struct timespec *reltime)
225 {
226     int64_t timeout_ms = 0;
227 
228     if ((cond == NULL) || (mutex == NULL)) {
229         return EINVAL;
230     }
231 
232     if (reltime == NULL) {
233         timeout_ms = AOS_WAIT_FOREVER;
234     } else {
235         timeout_ms = ((reltime->tv_sec) * 1000) + ((reltime->tv_nsec) / 1000000);
236         if (timeout_ms <= 0) {
237             return ETIMEDOUT;
238         }
239     }
240 
241     return pthread_cond_timedwait_ms(cond, mutex, timeout_ms);
242 }
243 
pthread_cond_wait(pthread_cond_t * cond,pthread_mutex_t * mutex)244 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
245 {
246     return pthread_cond_timedwait(cond, mutex, NULL);
247 }
248 
pthread_condattr_init(pthread_condattr_t * attr)249 int pthread_condattr_init(pthread_condattr_t *attr)
250 {
251     if (attr == NULL) {
252         return EINVAL;
253     }
254 
255     attr->flag = PTHREAD_DYN_INIT;
256     attr->clock   = DEFAULT_COND_CLOCK;
257     attr->pshared = DEFAULT_COND_SHARED;
258 
259     return 0;
260 }
261 
pthread_condattr_destroy(pthread_condattr_t * attr)262 int pthread_condattr_destroy(pthread_condattr_t *attr)
263 {
264     if (attr == NULL) {
265         return EINVAL;
266     }
267 
268     memset(attr, 0 ,sizeof(pthread_condattr_t));
269 
270     return 0;
271 }
272 
pthread_condattr_getclock(const pthread_condattr_t * attr,clockid_t * clock_id)273 int pthread_condattr_getclock(const pthread_condattr_t *attr, clockid_t *clock_id)
274 {
275     if ((attr == NULL) || (clock_id == NULL)) {
276         return EINVAL;
277     }
278 
279     *clock_id = attr->clock;
280 
281     return 0;
282 }
283 
pthread_condattr_setclock(pthread_condattr_t * attr,clockid_t clock_id)284 int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id)
285 {
286     if (attr == NULL) {
287         return EINVAL;
288     }
289 
290     if ((clock_id != CLOCK_REALTIME) && (clock_id != CLOCK_MONOTONIC)) {
291         return EINVAL;
292     }
293 
294     attr->clock = clock_id;
295 
296     return 0;
297 }
298