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