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