xref: /nrf52832-nimble/rt-thread/components/libc/pthreads/semaphore.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2010-10-26     Bernard      the first version
9*10465441SEvalZero  */
10*10465441SEvalZero 
11*10465441SEvalZero #include <rtthread.h>
12*10465441SEvalZero #include <string.h>
13*10465441SEvalZero #include "semaphore.h"
14*10465441SEvalZero #include "pthread_internal.h"
15*10465441SEvalZero 
16*10465441SEvalZero static sem_t *posix_sem_list = RT_NULL;
17*10465441SEvalZero static struct rt_semaphore posix_sem_lock;
posix_sem_system_init()18*10465441SEvalZero void posix_sem_system_init()
19*10465441SEvalZero {
20*10465441SEvalZero     rt_sem_init(&posix_sem_lock, "psem", 1, RT_IPC_FLAG_FIFO);
21*10465441SEvalZero }
22*10465441SEvalZero 
posix_sem_insert(sem_t * psem)23*10465441SEvalZero rt_inline void posix_sem_insert(sem_t *psem)
24*10465441SEvalZero {
25*10465441SEvalZero     psem->next = posix_sem_list;
26*10465441SEvalZero     posix_sem_list = psem;
27*10465441SEvalZero }
28*10465441SEvalZero 
posix_sem_delete(sem_t * psem)29*10465441SEvalZero static void posix_sem_delete(sem_t *psem)
30*10465441SEvalZero {
31*10465441SEvalZero     sem_t *iter;
32*10465441SEvalZero     if (posix_sem_list == psem)
33*10465441SEvalZero     {
34*10465441SEvalZero         posix_sem_list = psem->next;
35*10465441SEvalZero 
36*10465441SEvalZero         rt_sem_delete(psem->sem);
37*10465441SEvalZero         rt_free(psem);
38*10465441SEvalZero 
39*10465441SEvalZero         return;
40*10465441SEvalZero     }
41*10465441SEvalZero     for (iter = posix_sem_list; iter->next != RT_NULL; iter = iter->next)
42*10465441SEvalZero     {
43*10465441SEvalZero         if (iter->next == psem)
44*10465441SEvalZero         {
45*10465441SEvalZero             /* delete this mq */
46*10465441SEvalZero             if (psem->next != RT_NULL)
47*10465441SEvalZero                 iter->next = psem->next;
48*10465441SEvalZero             else
49*10465441SEvalZero                 iter->next = RT_NULL;
50*10465441SEvalZero 
51*10465441SEvalZero             /* delete RT-Thread mqueue */
52*10465441SEvalZero             rt_sem_delete(psem->sem);
53*10465441SEvalZero             rt_free(psem);
54*10465441SEvalZero 
55*10465441SEvalZero             return ;
56*10465441SEvalZero         }
57*10465441SEvalZero     }
58*10465441SEvalZero }
59*10465441SEvalZero 
posix_sem_find(const char * name)60*10465441SEvalZero static sem_t *posix_sem_find(const char* name)
61*10465441SEvalZero {
62*10465441SEvalZero     sem_t *iter;
63*10465441SEvalZero     rt_object_t object;
64*10465441SEvalZero 
65*10465441SEvalZero     for (iter = posix_sem_list; iter != RT_NULL; iter = iter->next)
66*10465441SEvalZero     {
67*10465441SEvalZero         object = (rt_object_t)&(iter->sem);
68*10465441SEvalZero 
69*10465441SEvalZero         if (strncmp(object->name, name, RT_NAME_MAX) == 0)
70*10465441SEvalZero         {
71*10465441SEvalZero             return iter;
72*10465441SEvalZero         }
73*10465441SEvalZero     }
74*10465441SEvalZero 
75*10465441SEvalZero     return RT_NULL;
76*10465441SEvalZero }
77*10465441SEvalZero 
sem_close(sem_t * sem)78*10465441SEvalZero int sem_close(sem_t *sem)
79*10465441SEvalZero {
80*10465441SEvalZero     if (sem == RT_NULL)
81*10465441SEvalZero     {
82*10465441SEvalZero         rt_set_errno(EINVAL);
83*10465441SEvalZero 
84*10465441SEvalZero         return -1;
85*10465441SEvalZero     }
86*10465441SEvalZero 
87*10465441SEvalZero     /* lock posix semaphore list */
88*10465441SEvalZero     rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
89*10465441SEvalZero     sem->refcount --;
90*10465441SEvalZero     if (sem->refcount == 0)
91*10465441SEvalZero     {
92*10465441SEvalZero         /* delete from posix semaphore list */
93*10465441SEvalZero         if (sem->unlinked)
94*10465441SEvalZero             posix_sem_delete(sem);
95*10465441SEvalZero         sem = RT_NULL;
96*10465441SEvalZero     }
97*10465441SEvalZero     rt_sem_release(&posix_sem_lock);
98*10465441SEvalZero 
99*10465441SEvalZero     return 0;
100*10465441SEvalZero }
101*10465441SEvalZero RTM_EXPORT(sem_close);
102*10465441SEvalZero 
sem_destroy(sem_t * sem)103*10465441SEvalZero int sem_destroy(sem_t *sem)
104*10465441SEvalZero {
105*10465441SEvalZero     rt_err_t result;
106*10465441SEvalZero 
107*10465441SEvalZero     if ((!sem) || !(sem->unamed))
108*10465441SEvalZero     {
109*10465441SEvalZero         rt_set_errno(EINVAL);
110*10465441SEvalZero 
111*10465441SEvalZero         return -1;
112*10465441SEvalZero     }
113*10465441SEvalZero 
114*10465441SEvalZero     /* lock posix semaphore list */
115*10465441SEvalZero     rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
116*10465441SEvalZero     result = rt_sem_trytake(sem->sem);
117*10465441SEvalZero     if (result != RT_EOK)
118*10465441SEvalZero     {
119*10465441SEvalZero         rt_sem_release(&posix_sem_lock);
120*10465441SEvalZero         rt_set_errno(EBUSY);
121*10465441SEvalZero 
122*10465441SEvalZero         return -1;
123*10465441SEvalZero     }
124*10465441SEvalZero 
125*10465441SEvalZero     /* destroy an unamed posix semaphore */
126*10465441SEvalZero     posix_sem_delete(sem);
127*10465441SEvalZero     rt_sem_release(&posix_sem_lock);
128*10465441SEvalZero 
129*10465441SEvalZero     return 0;
130*10465441SEvalZero }
131*10465441SEvalZero RTM_EXPORT(sem_destroy);
132*10465441SEvalZero 
sem_unlink(const char * name)133*10465441SEvalZero int sem_unlink(const char *name)
134*10465441SEvalZero {
135*10465441SEvalZero     sem_t *psem;
136*10465441SEvalZero 
137*10465441SEvalZero     /* lock posix semaphore list */
138*10465441SEvalZero     rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
139*10465441SEvalZero     psem = posix_sem_find(name);
140*10465441SEvalZero     if (psem != RT_NULL)
141*10465441SEvalZero     {
142*10465441SEvalZero         psem->unlinked = 1;
143*10465441SEvalZero         if (psem->refcount == 0)
144*10465441SEvalZero         {
145*10465441SEvalZero             /* remove this semaphore */
146*10465441SEvalZero             posix_sem_delete(psem);
147*10465441SEvalZero         }
148*10465441SEvalZero         rt_sem_release(&posix_sem_lock);
149*10465441SEvalZero 
150*10465441SEvalZero         return 0;
151*10465441SEvalZero     }
152*10465441SEvalZero     rt_sem_release(&posix_sem_lock);
153*10465441SEvalZero 
154*10465441SEvalZero     /* no this entry */
155*10465441SEvalZero     rt_set_errno(ENOENT);
156*10465441SEvalZero 
157*10465441SEvalZero     return -1;
158*10465441SEvalZero }
159*10465441SEvalZero RTM_EXPORT(sem_unlink);
160*10465441SEvalZero 
sem_getvalue(sem_t * sem,int * sval)161*10465441SEvalZero int sem_getvalue(sem_t *sem, int *sval)
162*10465441SEvalZero {
163*10465441SEvalZero     if (!sem || !sval)
164*10465441SEvalZero     {
165*10465441SEvalZero         rt_set_errno(EINVAL);
166*10465441SEvalZero 
167*10465441SEvalZero         return -1;
168*10465441SEvalZero     }
169*10465441SEvalZero     *sval = sem->sem->value;
170*10465441SEvalZero 
171*10465441SEvalZero     return 0;
172*10465441SEvalZero }
173*10465441SEvalZero RTM_EXPORT(sem_getvalue);
174*10465441SEvalZero 
sem_init(sem_t * sem,int pshared,unsigned int value)175*10465441SEvalZero int sem_init(sem_t *sem, int pshared, unsigned int value)
176*10465441SEvalZero {
177*10465441SEvalZero     char name[RT_NAME_MAX];
178*10465441SEvalZero     static rt_uint16_t psem_number = 0;
179*10465441SEvalZero 
180*10465441SEvalZero     if (sem == RT_NULL)
181*10465441SEvalZero     {
182*10465441SEvalZero         rt_set_errno(EINVAL);
183*10465441SEvalZero 
184*10465441SEvalZero         return -1;
185*10465441SEvalZero     }
186*10465441SEvalZero 
187*10465441SEvalZero     rt_snprintf(name, sizeof(name), "psem%02d", psem_number++);
188*10465441SEvalZero     sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO);
189*10465441SEvalZero     if (sem == RT_NULL)
190*10465441SEvalZero     {
191*10465441SEvalZero         rt_set_errno(ENOMEM);
192*10465441SEvalZero 
193*10465441SEvalZero         return -1;
194*10465441SEvalZero     }
195*10465441SEvalZero 
196*10465441SEvalZero     /* initialize posix semaphore */
197*10465441SEvalZero     sem->refcount = 1;
198*10465441SEvalZero     sem->unlinked = 0;
199*10465441SEvalZero     sem->unamed = 1;
200*10465441SEvalZero     /* lock posix semaphore list */
201*10465441SEvalZero     rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
202*10465441SEvalZero     posix_sem_insert(sem);
203*10465441SEvalZero     rt_sem_release(&posix_sem_lock);
204*10465441SEvalZero 
205*10465441SEvalZero     return 0;
206*10465441SEvalZero }
207*10465441SEvalZero RTM_EXPORT(sem_init);
208*10465441SEvalZero 
sem_open(const char * name,int oflag,...)209*10465441SEvalZero sem_t *sem_open(const char *name, int oflag, ...)
210*10465441SEvalZero {
211*10465441SEvalZero     sem_t* sem;
212*10465441SEvalZero     va_list arg;
213*10465441SEvalZero     mode_t mode;
214*10465441SEvalZero     unsigned int value;
215*10465441SEvalZero 
216*10465441SEvalZero     sem = RT_NULL;
217*10465441SEvalZero 
218*10465441SEvalZero     /* lock posix semaphore list */
219*10465441SEvalZero     rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
220*10465441SEvalZero     if (oflag & O_CREAT)
221*10465441SEvalZero     {
222*10465441SEvalZero         va_start(arg, oflag);
223*10465441SEvalZero         mode = (mode_t) va_arg( arg, unsigned int); mode = mode;
224*10465441SEvalZero         value = va_arg( arg, unsigned int);
225*10465441SEvalZero         va_end(arg);
226*10465441SEvalZero 
227*10465441SEvalZero         if (oflag & O_EXCL)
228*10465441SEvalZero         {
229*10465441SEvalZero             if (posix_sem_find(name) != RT_NULL)
230*10465441SEvalZero             {
231*10465441SEvalZero                 rt_set_errno(EEXIST);
232*10465441SEvalZero                 goto __return;
233*10465441SEvalZero             }
234*10465441SEvalZero         }
235*10465441SEvalZero         sem = (sem_t*) rt_malloc (sizeof(struct posix_sem));
236*10465441SEvalZero         if (sem == RT_NULL)
237*10465441SEvalZero         {
238*10465441SEvalZero             rt_set_errno(ENFILE);
239*10465441SEvalZero             goto __return;
240*10465441SEvalZero         }
241*10465441SEvalZero 
242*10465441SEvalZero         /* create RT-Thread semaphore */
243*10465441SEvalZero         sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO);
244*10465441SEvalZero         if (sem->sem == RT_NULL) /* create failed */
245*10465441SEvalZero         {
246*10465441SEvalZero             rt_set_errno(ENFILE);
247*10465441SEvalZero             goto __return;
248*10465441SEvalZero         }
249*10465441SEvalZero         /* initialize reference count */
250*10465441SEvalZero         sem->refcount = 1;
251*10465441SEvalZero         sem->unlinked = 0;
252*10465441SEvalZero         sem->unamed = 0;
253*10465441SEvalZero 
254*10465441SEvalZero         /* insert semaphore to posix semaphore list */
255*10465441SEvalZero         posix_sem_insert(sem);
256*10465441SEvalZero     }
257*10465441SEvalZero     else
258*10465441SEvalZero     {
259*10465441SEvalZero         /* find semaphore */
260*10465441SEvalZero         sem = posix_sem_find(name);
261*10465441SEvalZero         if (sem != RT_NULL)
262*10465441SEvalZero         {
263*10465441SEvalZero             sem->refcount ++; /* increase reference count */
264*10465441SEvalZero         }
265*10465441SEvalZero         else
266*10465441SEvalZero         {
267*10465441SEvalZero             rt_set_errno(ENOENT);
268*10465441SEvalZero             goto __return;
269*10465441SEvalZero         }
270*10465441SEvalZero     }
271*10465441SEvalZero     rt_sem_release(&posix_sem_lock);
272*10465441SEvalZero 
273*10465441SEvalZero     return sem;
274*10465441SEvalZero 
275*10465441SEvalZero __return:
276*10465441SEvalZero     /* release lock */
277*10465441SEvalZero     rt_sem_release(&posix_sem_lock);
278*10465441SEvalZero 
279*10465441SEvalZero     /* release allocated memory */
280*10465441SEvalZero     if (sem != RT_NULL)
281*10465441SEvalZero     {
282*10465441SEvalZero         /* delete RT-Thread semaphore */
283*10465441SEvalZero         if (sem->sem != RT_NULL)
284*10465441SEvalZero             rt_sem_delete(sem->sem);
285*10465441SEvalZero         rt_free(sem);
286*10465441SEvalZero     }
287*10465441SEvalZero 
288*10465441SEvalZero     return RT_NULL;
289*10465441SEvalZero }
290*10465441SEvalZero RTM_EXPORT(sem_open);
291*10465441SEvalZero 
sem_post(sem_t * sem)292*10465441SEvalZero int sem_post(sem_t *sem)
293*10465441SEvalZero {
294*10465441SEvalZero     rt_err_t result;
295*10465441SEvalZero 
296*10465441SEvalZero     if (!sem)
297*10465441SEvalZero     {
298*10465441SEvalZero         rt_set_errno(EINVAL);
299*10465441SEvalZero 
300*10465441SEvalZero         return -1;
301*10465441SEvalZero     }
302*10465441SEvalZero 
303*10465441SEvalZero     result = rt_sem_release(sem->sem);
304*10465441SEvalZero     if (result == RT_EOK)
305*10465441SEvalZero         return 0;
306*10465441SEvalZero 
307*10465441SEvalZero     rt_set_errno(EINVAL);
308*10465441SEvalZero 
309*10465441SEvalZero     return -1;
310*10465441SEvalZero }
311*10465441SEvalZero RTM_EXPORT(sem_post);
312*10465441SEvalZero 
sem_timedwait(sem_t * sem,const struct timespec * abs_timeout)313*10465441SEvalZero int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
314*10465441SEvalZero {
315*10465441SEvalZero     rt_err_t result;
316*10465441SEvalZero     rt_int32_t tick;
317*10465441SEvalZero 
318*10465441SEvalZero     if (!sem || !abs_timeout)
319*10465441SEvalZero         return EINVAL;
320*10465441SEvalZero 
321*10465441SEvalZero     /* calculate os tick */
322*10465441SEvalZero     tick = clock_time_to_tick(abs_timeout);
323*10465441SEvalZero 
324*10465441SEvalZero     result = rt_sem_take(sem->sem, tick);
325*10465441SEvalZero     if (result == -RT_ETIMEOUT)
326*10465441SEvalZero     {
327*10465441SEvalZero         rt_set_errno(ETIMEDOUT);
328*10465441SEvalZero 
329*10465441SEvalZero         return -1;
330*10465441SEvalZero     }
331*10465441SEvalZero     if (result == RT_EOK)
332*10465441SEvalZero         return 0;
333*10465441SEvalZero 
334*10465441SEvalZero     rt_set_errno(EINTR);
335*10465441SEvalZero 
336*10465441SEvalZero     return -1;
337*10465441SEvalZero }
338*10465441SEvalZero RTM_EXPORT(sem_timedwait);
339*10465441SEvalZero 
sem_trywait(sem_t * sem)340*10465441SEvalZero int sem_trywait(sem_t *sem)
341*10465441SEvalZero {
342*10465441SEvalZero     rt_err_t result;
343*10465441SEvalZero 
344*10465441SEvalZero     if (!sem)
345*10465441SEvalZero     {
346*10465441SEvalZero         rt_set_errno(EINVAL);
347*10465441SEvalZero 
348*10465441SEvalZero         return -1;
349*10465441SEvalZero     }
350*10465441SEvalZero 
351*10465441SEvalZero     result = rt_sem_take(sem->sem, 0);
352*10465441SEvalZero     if (result == -RT_ETIMEOUT)
353*10465441SEvalZero     {
354*10465441SEvalZero         rt_set_errno(EAGAIN);
355*10465441SEvalZero 
356*10465441SEvalZero         return -1;
357*10465441SEvalZero     }
358*10465441SEvalZero     if (result == RT_EOK)
359*10465441SEvalZero         return 0;
360*10465441SEvalZero 
361*10465441SEvalZero     rt_set_errno(EINTR);
362*10465441SEvalZero 
363*10465441SEvalZero     return -1;
364*10465441SEvalZero }
365*10465441SEvalZero RTM_EXPORT(sem_trywait);
366*10465441SEvalZero 
sem_wait(sem_t * sem)367*10465441SEvalZero int sem_wait(sem_t *sem)
368*10465441SEvalZero {
369*10465441SEvalZero     rt_err_t result;
370*10465441SEvalZero 
371*10465441SEvalZero     if (!sem)
372*10465441SEvalZero     {
373*10465441SEvalZero         rt_set_errno(EINVAL);
374*10465441SEvalZero 
375*10465441SEvalZero         return -1;
376*10465441SEvalZero     }
377*10465441SEvalZero 
378*10465441SEvalZero     result = rt_sem_take(sem->sem, RT_WAITING_FOREVER);
379*10465441SEvalZero     if (result == RT_EOK)
380*10465441SEvalZero         return 0;
381*10465441SEvalZero 
382*10465441SEvalZero     rt_set_errno(EINTR);
383*10465441SEvalZero 
384*10465441SEvalZero     return -1;
385*10465441SEvalZero }
386*10465441SEvalZero RTM_EXPORT(sem_wait);
387*10465441SEvalZero 
388