1 /*
2  * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3  */
4 
5 #include <errno.h>
6 #include <pthread.h>
7 #include <sched.h>
8 #include <aos/kernel.h>
9 
10 #include "internal/pthread.h"
11 
12 
13 #define PTHREAD_MUTEXATTR_IS_INITED(x) do { if ((x)->flag != PTHREAD_DYN_INIT) return EINVAL; } \
14                                        while (0)
15 
16 
pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t * attr)17 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
18 {
19     int ret = 0;
20 
21     if (mutex == NULL) {
22         return EINVAL;
23     }
24     memset(mutex, 0, sizeof(pthread_mutex_t));
25 
26     if (attr != NULL) {
27         mutex->attr = *attr;
28     }
29 
30     ret = aos_mutex_new((aos_mutex_t*)(&(mutex->mutex)));
31     if (ret != 0) {
32         return -1;
33     }
34 
35     mutex->flag = PTHREAD_DYN_INIT;
36     return 0;
37 }
38 
pthread_mutex_destroy(pthread_mutex_t * mutex)39 int pthread_mutex_destroy(pthread_mutex_t *mutex)
40 {
41     if (mutex == NULL) {
42         return EINVAL;
43     }
44 
45     if (mutex->flag == PTHREAD_STATIC_INIT) {
46         memset(mutex, 0, sizeof(pthread_mutex_t));
47         return 0;
48     } else if (mutex->flag == PTHREAD_DYN_INIT) {
49         aos_mutex_free((aos_mutex_t*)(&(mutex->mutex)));
50         memset(mutex, 0, sizeof(pthread_mutex_t));
51         return 0;
52     } else {
53         return EINVAL;
54     }
55 }
56 
pthread_mutex_lock(pthread_mutex_t * mutex)57 int pthread_mutex_lock(pthread_mutex_t *mutex)
58 {
59     int ret = 0;
60 
61     if (mutex == NULL) {
62         return EINVAL;
63     }
64 
65     /* The mutex is initted by PTHREAD_MUTEX_INITIALIZER */
66     if (mutex->flag == PTHREAD_STATIC_INIT) {
67         ret = pthread_mutex_init(mutex, NULL);
68         if (ret != 0) {
69             return -1;
70         }
71     }
72 
73     ret = aos_mutex_lock((aos_mutex_t*)(&(mutex->mutex)), AOS_WAIT_FOREVER);
74     if (ret != 0) {
75         return -1;
76     }
77 
78     return 0;
79 }
80 
pthread_mutex_unlock(pthread_mutex_t * mutex)81 int pthread_mutex_unlock(pthread_mutex_t *mutex)
82 {
83     int ret = 0;
84 
85     if (mutex == NULL) {
86         return EINVAL;
87     }
88 
89     if (mutex->flag != PTHREAD_DYN_INIT) {
90         return -1;
91     }
92 
93     ret = aos_mutex_unlock((aos_mutex_t*)(&(mutex->mutex)));
94     if (ret != 0) {
95         return -1;
96     }
97 
98     return 0;
99 }
100 
pthread_mutex_trylock(pthread_mutex_t * mutex)101 int pthread_mutex_trylock(pthread_mutex_t *mutex)
102 {
103     int ret = 0;
104 
105     if (mutex == NULL) {
106         return EINVAL;
107     }
108 
109     /* The mutex is initted by PTHREAD_MUTEX_INITIALIZER */
110     if (mutex->flag == PTHREAD_STATIC_INIT) {
111         ret = pthread_mutex_init(mutex, NULL);
112         if (ret != 0) {
113             return -1;
114         }
115     }
116 
117     ret = aos_mutex_lock((aos_mutex_t*)(&(mutex->mutex)), AOS_NO_WAIT);
118     if (ret == -ETIMEDOUT) {
119         return EBUSY;
120     } else if (ret != 0) {
121         return -1;
122     } else {
123         return 0;
124     }
125 }
126 
pthread_mutex_timedlock(pthread_mutex_t * mutex,const struct timespec * at)127 int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *at)
128 {
129     int ret = 0;
130 
131     if (mutex == NULL) {
132         return EINVAL;
133     }
134 
135     /* The mutex is initted by PTHREAD_MUTEX_INITIALIZER */
136     if (mutex->flag == PTHREAD_STATIC_INIT) {
137         ret = pthread_mutex_init(mutex, NULL);
138         if (ret != 0) {
139             return -1;
140         }
141     }
142 
143     ret = pthread_mutex_trylock(mutex);
144     if (ret != EBUSY) {
145         return ret;
146     }
147 
148     unsigned int timeout = at->tv_sec * 1000 +  at->tv_nsec / 1000;
149     ret = aos_mutex_lock((aos_mutex_t*)(&(mutex->mutex)), timeout);
150     if (ret != 0) {
151         return -1;
152     }
153 
154     return 0;
155 }
156 
pthread_mutex_getprioceiling(const pthread_mutex_t * mutex,int * prioceiling)157 int pthread_mutex_getprioceiling(const pthread_mutex_t *mutex, int *prioceiling)
158 {
159     if ((mutex == NULL) || (prioceiling == NULL)) {
160         return EINVAL;
161     }
162 
163     PTHREAD_MUTEXATTR_IS_INITED(&(mutex->attr));
164 
165     *prioceiling = mutex->attr.prioceiling;
166 
167     return 0;
168 }
169 
pthread_mutex_setprioceiling(pthread_mutex_t * mutex,int prioceiling,int * old_ceiling)170 int pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int prioceiling,
171                                  int *old_ceiling)
172 {
173     if (mutex == NULL) {
174         return EINVAL;
175     }
176 
177     if ((prioceiling < sched_get_priority_min(SCHED_FIFO)) ||
178         (prioceiling > sched_get_priority_max(SCHED_FIFO))) {
179         return EINVAL;
180     }
181 
182     PTHREAD_MUTEXATTR_IS_INITED(&(mutex->attr));
183 
184     if (old_ceiling != NULL) {
185         *old_ceiling = mutex->attr.prioceiling;
186     }
187 
188     mutex->attr.prioceiling = prioceiling;
189 
190     return 0;
191 }
192 
pthread_mutexattr_init(pthread_mutexattr_t * attr)193 int pthread_mutexattr_init(pthread_mutexattr_t *attr)
194 {
195     if (attr == NULL) {
196         return EINVAL;
197     }
198 
199     attr->flag = PTHREAD_DYN_INIT;
200     attr->type        = PTHREAD_MUTEX_DEFAULT;
201     attr->protocol    = DEFAULT_MUTEX_PROCOCOL;
202     attr->prioceiling = DEFAULT_MUTEX_PRIOCEILING;
203     attr->pshared     = DEFAULT_MUTEX_PSHARED;
204 
205     return 0;
206 }
207 
pthread_mutexattr_destroy(pthread_mutexattr_t * attr)208 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
209 {
210     if (attr == NULL) {
211         return EINVAL;
212     }
213 
214     memset(attr, 0, sizeof(pthread_mutexattr_t));
215 
216     return 0;
217 }
218 
pthread_mutexattr_gettype(const pthread_mutexattr_t * attr,int * type)219 int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
220 {
221     if ((attr == NULL) || (type == NULL)) {
222         return EINVAL;
223     }
224 
225     PTHREAD_MUTEXATTR_IS_INITED(attr);
226 
227     *type = attr->type;
228 
229     return 0;
230 }
231 
pthread_mutexattr_settype(pthread_mutexattr_t * attr,int type)232 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
233 {
234     if (attr == NULL) {
235         return EINVAL;
236     }
237 
238     if ((type < PTHREAD_MUTEX_NORMAL) || (type > PTHREAD_MUTEX_ERRORCHECK)) {
239         return EINVAL;
240     }
241 
242     PTHREAD_MUTEXATTR_IS_INITED(attr);
243 
244     attr->type = type;
245 
246     return 0;
247 }
248 
pthread_mutexattr_getprotocol(const pthread_mutexattr_t * attr,int * protocol)249 int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol)
250 {
251     if ((attr == NULL) || (protocol == NULL)) {
252         return EINVAL;
253     }
254 
255     PTHREAD_MUTEXATTR_IS_INITED(attr);
256 
257     *protocol = attr->protocol;
258 
259     return 0;
260 }
261 
pthread_mutexattr_setprotocol(pthread_mutexattr_t * attr,int protocol)262 int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol)
263 {
264     if (attr == NULL) {
265         return EINVAL;
266     }
267 
268     if ((protocol < PTHREAD_PRIO_NONE) || (protocol > PTHREAD_PRIO_PROTECT)) {
269         return EINVAL;
270     }
271 
272     PTHREAD_MUTEXATTR_IS_INITED(attr);
273 
274     attr->protocol = protocol;
275 
276     return 0;
277 }
278 
pthread_mutexattr_getprioceiling(const pthread_mutexattr_t * attr,int * prioceiling)279 int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr,
280                                      int *prioceiling)
281 {
282     if ((attr == NULL) || (prioceiling == NULL)) {
283         return EINVAL;
284     }
285 
286     PTHREAD_MUTEXATTR_IS_INITED(attr);
287 
288     *prioceiling = attr->prioceiling;
289 
290     return 0;
291 }
292 
pthread_mutexattr_setprioceiling(pthread_mutexattr_t * attr,int prioceiling)293 int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling)
294 {
295     if (attr == NULL) {
296         return EINVAL;
297     }
298 
299     if ((prioceiling < sched_get_priority_min(SCHED_FIFO)) ||
300         (prioceiling > sched_get_priority_max(SCHED_FIFO))) {
301         return EINVAL;
302     }
303 
304     PTHREAD_MUTEXATTR_IS_INITED(attr);
305 
306     attr->prioceiling = prioceiling;
307 
308     return 0;
309 }
310 
pthread_mutexattr_setpshared(pthread_mutexattr_t * attr,int pshared)311 int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
312 {
313     if (attr == NULL) {
314         return EINVAL;
315     }
316 
317     if ((pshared < PTHREAD_PROCESS_PRIVATE) || (pshared > PTHREAD_PROCESS_SHARED)) {
318         return EINVAL;
319     }
320 
321     PTHREAD_MUTEXATTR_IS_INITED(attr);
322 
323     attr->pshared = pshared;
324 
325     return 0;
326 }
327 
pthread_mutexattr_getpshared(pthread_mutexattr_t * attr,int * pshared)328 int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared)
329 {
330     if ((attr == NULL) || (pshared == NULL)) {
331         return EINVAL;
332     }
333 
334     PTHREAD_MUTEXATTR_IS_INITED(attr);
335 
336     *pshared = attr->pshared;
337 
338     return 0;
339 }
340