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