1 /* 2 * Copyright (C) 2010 David Xu <davidxu@freebsd.org>. 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 * the first lines of this file unmodified other than the possible 12 * addition of one or more copyright notices. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice(s), this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 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 * 30 * $FreeBSD$ 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 39 * because libc's stub for pthread_cond_wait() doesn't really wait, 40 * and it is not worth the effort impose this behavior on libc. 41 * 42 * All functions here are designed to be thread-safe so that a 43 * threads library need not provide wrappers except to make 44 * sem_wait() and sem_timedwait() cancellation points or to 45 * provide a faster userland implementation for non-pshared 46 * semaphores. 47 * 48 * Also, this implementation of semaphores cannot really support 49 * real pshared semaphores. The sem_t is an allocated object 50 * and can't be seen by other processes when placed in shared 51 * memory. It should work across forks as long as the semaphore 52 * is created before any forks. 53 * 54 * The function sem_init() should be overridden by a threads 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> 64 #include <errno.h> 65 #include <sys/umtx.h> 66 #include <sys/_semaphore.h> 67 #include <limits.h> 68 #include <fcntl.h> 69 #include <pthread.h> 70 #include <stdarg.h> 71 #include <stdlib.h> 72 #include <time.h> 73 #include "un-namespace.h" 74 #include "libc_private.h" 75 76 /* 77 * Old semaphore definitions. 78 */ 79 struct 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 93 typedef 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 WEAK_REF(sym, alias) __weak_reference(sym, alias) 100 #define SYM_COMPAT(sym, impl, ver) __sym_compat(sym, impl, ver) 101 102 #define FB10_COMPAT(func, sym) \ 103 WEAK_REF(func, SYM_FB10(sym)); \ 104 SYM_COMPAT(sym, SYM_FB10(sym), FBSD_1.0) 105 106 static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); 107 static void sem_free(sem_t sem); 108 109 static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(named_sems); 110 static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER; 111 112 FB10_COMPAT(_libc_sem_init_compat, sem_init); 113 FB10_COMPAT(_libc_sem_destroy_compat, sem_destroy); 114 FB10_COMPAT(_libc_sem_open_compat, sem_open); 115 FB10_COMPAT(_libc_sem_close_compat, sem_close); 116 FB10_COMPAT(_libc_sem_unlink_compat, sem_unlink); 117 FB10_COMPAT(_libc_sem_wait_compat, sem_wait); 118 FB10_COMPAT(_libc_sem_trywait_compat, sem_trywait); 119 FB10_COMPAT(_libc_sem_timedwait_compat, sem_timedwait); 120 FB10_COMPAT(_libc_sem_post_compat, sem_post); 121 FB10_COMPAT(_libc_sem_getvalue_compat, sem_getvalue); 122 123 static inline int 124 sem_check_validity(sem_t *sem) 125 { 126 127 if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC)) 128 return (0); 129 else { 130 errno = EINVAL; 131 return (-1); 132 } 133 } 134 135 static void 136 sem_free(sem_t sem) 137 { 138 139 sem->magic = 0; 140 free(sem); 141 } 142 143 static sem_t 144 sem_alloc(unsigned int value, semid_t semid, int system_sem) 145 { 146 sem_t sem; 147 148 if (value > SEM_VALUE_MAX) { 149 errno = EINVAL; 150 return (NULL); 151 } 152 153 sem = (sem_t)malloc(sizeof(struct sem)); 154 if (sem == NULL) { 155 errno = ENOSPC; 156 return (NULL); 157 } 158 159 sem->count = (u_int32_t)value; 160 sem->nwaiters = 0; 161 sem->magic = SEM_MAGIC; 162 sem->semid = semid; 163 sem->syssem = system_sem; 164 return (sem); 165 } 166 167 int 168 _libc_sem_init_compat(sem_t *sem, int pshared, unsigned int value) 169 { 170 semid_t semid; 171 172 /* 173 * We always have to create the kernel semaphore if the 174 * threads library isn't present since libc's version of 175 * pthread_cond_wait() is just a stub that doesn't really 176 * wait. 177 */ 178 semid = (semid_t)SEM_USER; 179 if ((pshared != 0) && ksem_init(&semid, value) != 0) 180 return (-1); 181 182 *sem = sem_alloc(value, semid, pshared); 183 if ((*sem) == NULL) { 184 if (pshared != 0) 185 ksem_destroy(semid); 186 return (-1); 187 } 188 return (0); 189 } 190 191 int 192 _libc_sem_destroy_compat(sem_t *sem) 193 { 194 int retval; 195 196 if (sem_check_validity(sem) != 0) 197 return (-1); 198 199 /* 200 * If this is a system semaphore let the kernel track it otherwise 201 * make sure there are no waiters. 202 */ 203 if ((*sem)->syssem != 0) 204 retval = ksem_destroy((*sem)->semid); 205 else if ((*sem)->nwaiters > 0) { 206 errno = EBUSY; 207 retval = -1; 208 } 209 else { 210 retval = 0; 211 (*sem)->magic = 0; 212 } 213 214 if (retval == 0) 215 sem_free(*sem); 216 return (retval); 217 } 218 219 sem_t * 220 _libc_sem_open_compat(const char *name, int oflag, ...) 221 { 222 sem_t *sem; 223 sem_t s; 224 semid_t semid; 225 mode_t mode; 226 unsigned int value; 227 228 mode = 0; 229 value = 0; 230 231 if ((oflag & O_CREAT) != 0) { 232 va_list ap; 233 234 va_start(ap, oflag); 235 mode = va_arg(ap, int); 236 value = va_arg(ap, unsigned int); 237 va_end(ap); 238 } 239 /* 240 * we can be lazy and let the kernel handle the "oflag", 241 * we'll just merge duplicate IDs into our list. 242 */ 243 if (ksem_open(&semid, name, oflag, mode, value) == -1) 244 return (SEM_FAILED); 245 /* 246 * search for a duplicate ID, we must return the same sem_t * 247 * if we locate one. 248 */ 249 _pthread_mutex_lock(&named_sems_mtx); 250 LIST_FOREACH(s, &named_sems, entry) { 251 if (s->semid == semid) { 252 sem = s->backpointer; 253 _pthread_mutex_unlock(&named_sems_mtx); 254 return (sem); 255 } 256 } 257 sem = (sem_t *)malloc(sizeof(*sem)); 258 if (sem == NULL) 259 goto err; 260 *sem = sem_alloc(value, semid, 1); 261 if ((*sem) == NULL) 262 goto err; 263 LIST_INSERT_HEAD(&named_sems, *sem, entry); 264 (*sem)->backpointer = sem; 265 _pthread_mutex_unlock(&named_sems_mtx); 266 return (sem); 267 err: 268 _pthread_mutex_unlock(&named_sems_mtx); 269 ksem_close(semid); 270 if (sem != NULL) { 271 if (*sem != NULL) 272 sem_free(*sem); 273 else 274 errno = ENOSPC; 275 free(sem); 276 } else { 277 errno = ENOSPC; 278 } 279 return (SEM_FAILED); 280 } 281 282 int 283 _libc_sem_close_compat(sem_t *sem) 284 { 285 286 if (sem_check_validity(sem) != 0) 287 return (-1); 288 289 if ((*sem)->syssem == 0) { 290 errno = EINVAL; 291 return (-1); 292 } 293 294 _pthread_mutex_lock(&named_sems_mtx); 295 if (ksem_close((*sem)->semid) != 0) { 296 _pthread_mutex_unlock(&named_sems_mtx); 297 return (-1); 298 } 299 LIST_REMOVE((*sem), entry); 300 _pthread_mutex_unlock(&named_sems_mtx); 301 sem_free(*sem); 302 *sem = NULL; 303 free(sem); 304 return (0); 305 } 306 307 int 308 _libc_sem_unlink_compat(const char *name) 309 { 310 311 return (ksem_unlink(name)); 312 } 313 314 static int 315 _umtx_wait_uint(volatile unsigned *mtx, unsigned id, const struct timespec *timeout) 316 { 317 if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 && 318 timeout->tv_nsec <= 0))) { 319 errno = ETIMEDOUT; 320 return (-1); 321 } 322 return _umtx_op(__DEVOLATILE(void *, mtx), 323 UMTX_OP_WAIT_UINT_PRIVATE, id, NULL, __DECONST(void*, timeout)); 324 } 325 326 static int 327 _umtx_wake(volatile void *mtx) 328 { 329 return _umtx_op(__DEVOLATILE(void *, mtx), UMTX_OP_WAKE_PRIVATE, 330 1, NULL, NULL); 331 } 332 333 #define TIMESPEC_SUB(dst, src, val) \ 334 do { \ 335 (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \ 336 (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \ 337 if ((dst)->tv_nsec < 0) { \ 338 (dst)->tv_sec--; \ 339 (dst)->tv_nsec += 1000000000; \ 340 } \ 341 } while (0) 342 343 344 static void 345 sem_cancel_handler(void *arg) 346 { 347 sem_t *sem = arg; 348 349 atomic_add_int(&(*sem)->nwaiters, -1); 350 if ((*sem)->nwaiters && (*sem)->count) 351 _umtx_wake(&(*sem)->count); 352 } 353 354 int 355 _libc_sem_timedwait_compat(sem_t * __restrict sem, 356 const struct timespec * __restrict abstime) 357 { 358 struct timespec ts, ts2; 359 int val, retval; 360 361 if (sem_check_validity(sem) != 0) 362 return (-1); 363 364 if ((*sem)->syssem != 0) { 365 _pthread_cancel_enter(1); 366 retval = ksem_wait((*sem)->semid); /* XXX no timeout */ 367 _pthread_cancel_leave(retval == -1); 368 return (retval); 369 } 370 371 retval = 0; 372 _pthread_testcancel(); 373 for (;;) { 374 while ((val = (*sem)->count) > 0) { 375 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) 376 return (0); 377 } 378 if (retval) { 379 _pthread_testcancel(); 380 break; 381 } 382 if (abstime) { 383 if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) { 384 errno = EINVAL; 385 return (-1); 386 } 387 clock_gettime(CLOCK_REALTIME, &ts); 388 TIMESPEC_SUB(&ts2, abstime, &ts); 389 } 390 atomic_add_int(&(*sem)->nwaiters, 1); 391 pthread_cleanup_push(sem_cancel_handler, sem); 392 _pthread_cancel_enter(1); 393 retval = _umtx_wait_uint(&(*sem)->count, 0, abstime ? &ts2 : NULL); 394 _pthread_cancel_leave(0); 395 pthread_cleanup_pop(0); 396 atomic_add_int(&(*sem)->nwaiters, -1); 397 } 398 return (retval); 399 } 400 401 int 402 _libc_sem_wait_compat(sem_t *sem) 403 { 404 return _libc_sem_timedwait_compat(sem, NULL); 405 } 406 407 int 408 _libc_sem_trywait_compat(sem_t *sem) 409 { 410 int val; 411 412 if (sem_check_validity(sem) != 0) 413 return (-1); 414 415 if ((*sem)->syssem != 0) 416 return ksem_trywait((*sem)->semid); 417 418 while ((val = (*sem)->count) > 0) { 419 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) 420 return (0); 421 } 422 errno = EAGAIN; 423 return (-1); 424 } 425 426 int 427 _libc_sem_post_compat(sem_t *sem) 428 { 429 430 if (sem_check_validity(sem) != 0) 431 return (-1); 432 433 if ((*sem)->syssem != 0) 434 return ksem_post((*sem)->semid); 435 436 atomic_add_rel_int(&(*sem)->count, 1); 437 438 if ((*sem)->nwaiters) 439 return _umtx_wake(&(*sem)->count); 440 return (0); 441 } 442 443 int 444 _libc_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval) 445 { 446 int retval; 447 448 if (sem_check_validity(sem) != 0) 449 return (-1); 450 451 if ((*sem)->syssem != 0) 452 retval = ksem_getvalue((*sem)->semid, sval); 453 else { 454 *sval = (int)(*sem)->count; 455 retval = 0; 456 } 457 return (retval); 458 } 459