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} |