Deleted Added
full compact
sem.c (201145) sem.c (201546)
1/*
1/*
2 * Copyright (C) 2010 David Xu <davidxu@freebsd.org>.
2 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice(s), this list of conditions and the following disclaimer as

--- 11 unchanged lines hidden (view full) ---

21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
3 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice(s), this list of conditions and the following disclaimer as

--- 11 unchanged lines hidden (view full) ---

22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
29 * $FreeBSD: head/lib/libc/gen/sem.c 201145 2009-12-28 22:56:30Z antoine $
30 * $FreeBSD: head/lib/libc/gen/sem.c 201546 2010-01-05 02:37:59Z davidxu $
30 */
31
32/*
33 * Some notes about this implementation.
34 *
35 * This is mostly a simple implementation of POSIX semaphores that
36 * does not need threading. Any semaphore created is a kernel-based
37 * semaphore regardless of the pshared attribute. This is necessary

--- 16 unchanged lines hidden (view full) ---

54 * library if it wants to provide a different userland version
55 * of semaphores. The functions sem_wait() and sem_timedwait()
56 * need to be wrapped to provide cancellation points. The function
57 * sem_post() may need to be wrapped to be signal-safe.
58 */
59#include "namespace.h"
60#include <sys/types.h>
61#include <sys/queue.h>
31 */
32
33/*
34 * Some notes about this implementation.
35 *
36 * This is mostly a simple implementation of POSIX semaphores that
37 * does not need threading. Any semaphore created is a kernel-based
38 * semaphore regardless of the pshared attribute. This is necessary

--- 16 unchanged lines hidden (view full) ---

55 * library if it wants to provide a different userland version
56 * of semaphores. The functions sem_wait() and sem_timedwait()
57 * need to be wrapped to provide cancellation points. The function
58 * sem_post() may need to be wrapped to be signal-safe.
59 */
60#include "namespace.h"
61#include <sys/types.h>
62#include <sys/queue.h>
63#include <machine/atomic.h>
62#include <errno.h>
64#include <errno.h>
65#include <sys/umtx.h>
66#include <sys/_semaphore.h>
67#include <limits.h>
63#include <fcntl.h>
64#include <pthread.h>
68#include <fcntl.h>
69#include <pthread.h>
65#include <semaphore.h>
66#include <stdarg.h>
67#include <stdlib.h>
68#include <time.h>
70#include <stdarg.h>
71#include <stdlib.h>
72#include <time.h>
69#include <_semaphore.h>
70#include "un-namespace.h"
71#include "libc_private.h"
72
73#include "un-namespace.h"
74#include "libc_private.h"
75
76/*
77 * Old semaphore definitions.
78 */
79struct sem {
80#define SEM_MAGIC ((u_int32_t) 0x09fa4012)
81 u_int32_t magic;
82 pthread_mutex_t lock;
83 pthread_cond_t gtzero;
84 u_int32_t count;
85 u_int32_t nwaiters;
86#define SEM_USER (NULL)
87 semid_t semid; /* semaphore id if kernel (shared) semaphore */
88 int syssem; /* 1 if kernel (shared) semaphore */
89 LIST_ENTRY(sem) entry;
90 struct sem **backpointer;
91};
92
93typedef struct sem* sem_t;
94
95#define SEM_FAILED ((sem_t *)0)
96#define SEM_VALUE_MAX __INT_MAX
97
98#define SYM_FB10(sym) __CONCAT(sym, _fb10)
99#define SYM_FBP10(sym) __CONCAT(sym, _fbp10)
100#define WEAK_REF(sym, alias) __weak_reference(sym, alias)
101#define SYM_COMPAT(sym, impl, ver) __sym_compat(sym, impl, ver)
102#define SYM_DEFAULT(sym, impl, ver) __sym_default(sym, impl, ver)
103
104#define FB10_COMPAT(func, sym) \
105 WEAK_REF(func, SYM_FB10(sym)); \
106 SYM_COMPAT(sym, SYM_FB10(sym), FBSD_1.0)
107
108#define FB10_COMPAT_PRIVATE(func, sym) \
109 WEAK_REF(func, SYM_FBP10(sym)); \
110 SYM_DEFAULT(sym, SYM_FBP10(sym), FBSDprivate_1.0)
111
73static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem);
74static void sem_free(sem_t sem);
75
112static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem);
113static void sem_free(sem_t sem);
114
76static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(named_sems);
115static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(&named_sems);
77static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER;
78
116static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER;
117
79__weak_reference(__sem_init, sem_init);
80__weak_reference(__sem_destroy, sem_destroy);
81__weak_reference(__sem_open, sem_open);
82__weak_reference(__sem_close, sem_close);
83__weak_reference(__sem_unlink, sem_unlink);
84__weak_reference(__sem_wait, sem_wait);
85__weak_reference(__sem_trywait, sem_trywait);
86__weak_reference(__sem_timedwait, sem_timedwait);
87__weak_reference(__sem_post, sem_post);
88__weak_reference(__sem_getvalue, sem_getvalue);
118FB10_COMPAT(_libc_sem_init_compat, sem_init);
119FB10_COMPAT(_libc_sem_destroy_compat, sem_destroy);
120FB10_COMPAT(_libc_sem_open_compat, sem_open);
121FB10_COMPAT(_libc_sem_close_compat, sem_close);
122FB10_COMPAT(_libc_sem_unlink_compat, sem_unlink);
123FB10_COMPAT(_libc_sem_wait_compat, sem_wait);
124FB10_COMPAT(_libc_sem_trywait_compat, sem_trywait);
125FB10_COMPAT(_libc_sem_timedwait_compat, sem_timedwait);
126FB10_COMPAT(_libc_sem_post_compat, sem_post);
127FB10_COMPAT(_libc_sem_getvalue_compat, sem_getvalue);
89
128
90
91static inline int
92sem_check_validity(sem_t *sem)
93{
94
95 if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC))
96 return (0);
97 else {
98 errno = EINVAL;
99 return (-1);
100 }
101}
102
103static void
104sem_free(sem_t sem)
105{
106
129static inline int
130sem_check_validity(sem_t *sem)
131{
132
133 if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC))
134 return (0);
135 else {
136 errno = EINVAL;
137 return (-1);
138 }
139}
140
141static void
142sem_free(sem_t sem)
143{
144
107 _pthread_mutex_destroy(&sem->lock);
108 _pthread_cond_destroy(&sem->gtzero);
109 sem->magic = 0;
110 free(sem);
111}
112
113static sem_t
114sem_alloc(unsigned int value, semid_t semid, int system_sem)
115{
116 sem_t sem;

--- 9 unchanged lines hidden (view full) ---

126 return (NULL);
127 }
128
129 sem->count = (u_int32_t)value;
130 sem->nwaiters = 0;
131 sem->magic = SEM_MAGIC;
132 sem->semid = semid;
133 sem->syssem = system_sem;
145 sem->magic = 0;
146 free(sem);
147}
148
149static sem_t
150sem_alloc(unsigned int value, semid_t semid, int system_sem)
151{
152 sem_t sem;

--- 9 unchanged lines hidden (view full) ---

162 return (NULL);
163 }
164
165 sem->count = (u_int32_t)value;
166 sem->nwaiters = 0;
167 sem->magic = SEM_MAGIC;
168 sem->semid = semid;
169 sem->syssem = system_sem;
134 sem->lock = PTHREAD_MUTEX_INITIALIZER;
135 sem->gtzero = PTHREAD_COND_INITIALIZER;
136 return (sem);
137}
138
139int
170 return (sem);
171}
172
173int
140__sem_init(sem_t *sem, int pshared, unsigned int value)
174_libc_sem_init_compat(sem_t *sem, int pshared, unsigned int value)
141{
142 semid_t semid;
143
144 /*
145 * We always have to create the kernel semaphore if the
146 * threads library isn't present since libc's version of
147 * pthread_cond_wait() is just a stub that doesn't really
148 * wait.
149 */
175{
176 semid_t semid;
177
178 /*
179 * We always have to create the kernel semaphore if the
180 * threads library isn't present since libc's version of
181 * pthread_cond_wait() is just a stub that doesn't really
182 * wait.
183 */
150 if (ksem_init(&semid, value) != 0)
184 semid = (semid_t)SEM_USER;
185 if ((pshared != 0) && ksem_init(&semid, value) != 0)
151 return (-1);
152
186 return (-1);
187
153 (*sem) = sem_alloc(value, semid, 1);
188 *sem = sem_alloc(value, semid, pshared);
154 if ((*sem) == NULL) {
189 if ((*sem) == NULL) {
155 ksem_destroy(semid);
190 if (pshared != 0)
191 ksem_destroy(semid);
156 return (-1);
157 }
158 return (0);
159}
160
161int
192 return (-1);
193 }
194 return (0);
195}
196
197int
162__sem_destroy(sem_t *sem)
198_libc_sem_destroy_compat(sem_t *sem)
163{
164 int retval;
165
166 if (sem_check_validity(sem) != 0)
167 return (-1);
168
199{
200 int retval;
201
202 if (sem_check_validity(sem) != 0)
203 return (-1);
204
169 _pthread_mutex_lock(&(*sem)->lock);
170 /*
171 * If this is a system semaphore let the kernel track it otherwise
172 * make sure there are no waiters.
173 */
174 if ((*sem)->syssem != 0)
175 retval = ksem_destroy((*sem)->semid);
176 else if ((*sem)->nwaiters > 0) {
177 errno = EBUSY;
178 retval = -1;
179 }
180 else {
181 retval = 0;
182 (*sem)->magic = 0;
183 }
205 /*
206 * If this is a system semaphore let the kernel track it otherwise
207 * make sure there are no waiters.
208 */
209 if ((*sem)->syssem != 0)
210 retval = ksem_destroy((*sem)->semid);
211 else if ((*sem)->nwaiters > 0) {
212 errno = EBUSY;
213 retval = -1;
214 }
215 else {
216 retval = 0;
217 (*sem)->magic = 0;
218 }
184 _pthread_mutex_unlock(&(*sem)->lock);
185
219
186 if (retval == 0) {
187 _pthread_mutex_destroy(&(*sem)->lock);
188 _pthread_cond_destroy(&(*sem)->gtzero);
220 if (retval == 0)
189 sem_free(*sem);
221 sem_free(*sem);
190 }
191 return (retval);
192}
193
194sem_t *
222 return (retval);
223}
224
225sem_t *
195__sem_open(const char *name, int oflag, ...)
226_libc_sem_open_compat(const char *name, int oflag, ...)
196{
197 sem_t *sem;
198 sem_t s;
199 semid_t semid;
200 mode_t mode;
201 unsigned int value;
202
203 mode = 0;

--- 46 unchanged lines hidden (view full) ---

250 free(sem);
251 } else {
252 errno = ENOSPC;
253 }
254 return (SEM_FAILED);
255}
256
257int
227{
228 sem_t *sem;
229 sem_t s;
230 semid_t semid;
231 mode_t mode;
232 unsigned int value;
233
234 mode = 0;

--- 46 unchanged lines hidden (view full) ---

281 free(sem);
282 } else {
283 errno = ENOSPC;
284 }
285 return (SEM_FAILED);
286}
287
288int
258__sem_close(sem_t *sem)
289_libc_sem_close_compat(sem_t *sem)
259{
260
261 if (sem_check_validity(sem) != 0)
262 return (-1);
263
264 if ((*sem)->syssem == 0) {
265 errno = EINVAL;
266 return (-1);

--- 8 unchanged lines hidden (view full) ---

275 _pthread_mutex_unlock(&named_sems_mtx);
276 sem_free(*sem);
277 *sem = NULL;
278 free(sem);
279 return (0);
280}
281
282int
290{
291
292 if (sem_check_validity(sem) != 0)
293 return (-1);
294
295 if ((*sem)->syssem == 0) {
296 errno = EINVAL;
297 return (-1);

--- 8 unchanged lines hidden (view full) ---

306 _pthread_mutex_unlock(&named_sems_mtx);
307 sem_free(*sem);
308 *sem = NULL;
309 free(sem);
310 return (0);
311}
312
313int
283__sem_unlink(const char *name)
314_libc_sem_unlink_compat(const char *name)
284{
285
286 return (ksem_unlink(name));
287}
288
315{
316
317 return (ksem_unlink(name));
318}
319
289int
290__sem_wait(sem_t *sem)
320static int
321enable_async_cancel(void)
291{
322{
323 int old;
292
324
293 if (sem_check_validity(sem) != 0)
325 _pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);
326 return (old);
327}
328
329static void
330restore_async_cancel(int val)
331{
332 _pthread_setcanceltype(val, NULL);
333}
334
335static int
336_umtx_wait_uint(volatile unsigned *mtx, unsigned id, const struct timespec *timeout)
337{
338 if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 &&
339 timeout->tv_nsec <= 0))) {
340 errno = ETIMEDOUT;
294 return (-1);
341 return (-1);
342 }
343 return _umtx_op(__DEVOLATILE(void *, mtx),
344 UMTX_OP_WAIT_UINT_PRIVATE, id, NULL, __DECONST(void*, timeout));
345}
295
346
296 return (ksem_wait((*sem)->semid));
347static int
348_umtx_wake(volatile void *mtx)
349{
350 return _umtx_op(__DEVOLATILE(void *, mtx), UMTX_OP_WAKE_PRIVATE,
351 1, NULL, NULL);
297}
298
352}
353
354#define TIMESPEC_SUB(dst, src, val) \
355 do { \
356 (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \
357 (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \
358 if ((dst)->tv_nsec < 0) { \
359 (dst)->tv_sec--; \
360 (dst)->tv_nsec += 1000000000; \
361 } \
362 } while (0)
363
364
365static void
366sem_cancel_handler(void *arg)
367{
368 sem_t *sem = arg;
369
370 atomic_add_int(&(*sem)->nwaiters, -1);
371 if ((*sem)->nwaiters && (*sem)->count)
372 _umtx_wake(&(*sem)->count);
373}
374
299int
375int
300__sem_trywait(sem_t *sem)
376_libc_sem_timedwait_compat(sem_t * __restrict sem,
377 const struct timespec * __restrict abstime)
301{
378{
302 int retval;
379 struct timespec ts, ts2;
380 int val, retval, saved_cancel;
303
304 if (sem_check_validity(sem) != 0)
305 return (-1);
306
381
382 if (sem_check_validity(sem) != 0)
383 return (-1);
384
307 if ((*sem)->syssem != 0)
308 retval = ksem_trywait((*sem)->semid);
309 else {
310 _pthread_mutex_lock(&(*sem)->lock);
311 if ((*sem)->count > 0) {
312 (*sem)->count--;
313 retval = 0;
314 } else {
315 errno = EAGAIN;
316 retval = -1;
385 if ((*sem)->syssem != 0) {
386 saved_cancel = enable_async_cancel();
387 retval = ksem_wait((*sem)->semid);
388 restore_async_cancel(saved_cancel);
389 return (retval);
390 }
391
392 retval = 0;
393 _pthread_testcancel();
394 for (;;) {
395 while ((val = (*sem)->count) > 0) {
396 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
397 return (0);
317 }
398 }
318 _pthread_mutex_unlock(&(*sem)->lock);
399 if (retval)
400 break;
401 if (abstime) {
402 if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) {
403 errno = EINVAL;
404 return (-1);
405 }
406 clock_gettime(CLOCK_REALTIME, &ts);
407 TIMESPEC_SUB(&ts2, abstime, &ts);
408 }
409 atomic_add_int(&(*sem)->nwaiters, 1);
410 pthread_cleanup_push(sem_cancel_handler, sem);
411 saved_cancel = enable_async_cancel();
412 retval = _umtx_wait_uint(&(*sem)->count, 0, abstime ? &ts2 : NULL);
413 restore_async_cancel(saved_cancel);
414 pthread_cleanup_pop(0);
415 atomic_add_int(&(*sem)->nwaiters, -1);
319 }
320 return (retval);
321}
322
323int
416 }
417 return (retval);
418}
419
420int
324__sem_timedwait(sem_t * __restrict sem,
325 const struct timespec * __restrict abs_timeout)
421_libc_sem_wait_compat(sem_t *sem)
326{
422{
423 return _libc_sem_timedwait_compat(sem, NULL);
424}
425
426int
427_libc_sem_trywait_compat(sem_t *sem)
428{
429 int val;
430
327 if (sem_check_validity(sem) != 0)
328 return (-1);
329
431 if (sem_check_validity(sem) != 0)
432 return (-1);
433
330 return (ksem_timedwait((*sem)->semid, abs_timeout));
434 if ((*sem)->syssem != 0)
435 return ksem_trywait((*sem)->semid);
436
437 while ((val = (*sem)->count) > 0) {
438 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
439 return (0);
440 }
441 errno = EAGAIN;
442 return (-1);
331}
332
333int
443}
444
445int
334__sem_post(sem_t *sem)
446_libc_sem_post_compat(sem_t *sem)
335{
336
337 if (sem_check_validity(sem) != 0)
338 return (-1);
339
447{
448
449 if (sem_check_validity(sem) != 0)
450 return (-1);
451
340 return (ksem_post((*sem)->semid));
452 if ((*sem)->syssem != 0)
453 return ksem_post((*sem)->semid);
454
455 atomic_add_rel_int(&(*sem)->count, 1);
456
457 if ((*sem)->nwaiters)
458 return _umtx_wake(&(*sem)->count);
459 return (0);
341}
342
343int
460}
461
462int
344__sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
463_libc_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval)
345{
346 int retval;
347
348 if (sem_check_validity(sem) != 0)
349 return (-1);
350
351 if ((*sem)->syssem != 0)
352 retval = ksem_getvalue((*sem)->semid, sval);
353 else {
464{
465 int retval;
466
467 if (sem_check_validity(sem) != 0)
468 return (-1);
469
470 if ((*sem)->syssem != 0)
471 retval = ksem_getvalue((*sem)->semid, sval);
472 else {
354 _pthread_mutex_lock(&(*sem)->lock);
355 *sval = (int)(*sem)->count;
473 *sval = (int)(*sem)->count;
356 _pthread_mutex_unlock(&(*sem)->lock);
357
358 retval = 0;
359 }
360 return (retval);
361}
474 retval = 0;
475 }
476 return (retval);
477}