1bf4dc877SAlfred Perlstein /* 29b0f1823SDavid Xu * Copyright (C) 2010 David Xu <davidxu@freebsd.org>. 3bf4dc877SAlfred Perlstein * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. 4bf4dc877SAlfred Perlstein * All rights reserved. 5bf4dc877SAlfred Perlstein * 6bf4dc877SAlfred Perlstein * Redistribution and use in source and binary forms, with or without 7bf4dc877SAlfred Perlstein * modification, are permitted provided that the following conditions 8bf4dc877SAlfred Perlstein * are met: 9bf4dc877SAlfred Perlstein * 1. Redistributions of source code must retain the above copyright 10bf4dc877SAlfred Perlstein * notice(s), this list of conditions and the following disclaimer as 11bf4dc877SAlfred Perlstein * the first lines of this file unmodified other than the possible 12bf4dc877SAlfred Perlstein * addition of one or more copyright notices. 13bf4dc877SAlfred Perlstein * 2. Redistributions in binary form must reproduce the above copyright 14bf4dc877SAlfred Perlstein * notice(s), this list of conditions and the following disclaimer in 15bf4dc877SAlfred Perlstein * the documentation and/or other materials provided with the 16bf4dc877SAlfred Perlstein * distribution. 17bf4dc877SAlfred Perlstein * 18bf4dc877SAlfred Perlstein * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 19bf4dc877SAlfred Perlstein * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20bf4dc877SAlfred Perlstein * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21bf4dc877SAlfred Perlstein * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 22bf4dc877SAlfred Perlstein * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23bf4dc877SAlfred Perlstein * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24bf4dc877SAlfred Perlstein * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 25bf4dc877SAlfred Perlstein * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26bf4dc877SAlfred Perlstein * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 27bf4dc877SAlfred Perlstein * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 28bf4dc877SAlfred Perlstein * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29bf4dc877SAlfred Perlstein * 30bf4dc877SAlfred Perlstein * $FreeBSD$ 31bf4dc877SAlfred Perlstein */ 32bf4dc877SAlfred Perlstein 335c70dac8SDaniel Eischen /* 345c70dac8SDaniel Eischen * Some notes about this implementation. 355c70dac8SDaniel Eischen * 365c70dac8SDaniel Eischen * This is mostly a simple implementation of POSIX semaphores that 375c70dac8SDaniel Eischen * does not need threading. Any semaphore created is a kernel-based 385c70dac8SDaniel Eischen * semaphore regardless of the pshared attribute. This is necessary 395c70dac8SDaniel Eischen * because libc's stub for pthread_cond_wait() doesn't really wait, 405c70dac8SDaniel Eischen * and it is not worth the effort impose this behavior on libc. 415c70dac8SDaniel Eischen * 425c70dac8SDaniel Eischen * All functions here are designed to be thread-safe so that a 435c70dac8SDaniel Eischen * threads library need not provide wrappers except to make 445c70dac8SDaniel Eischen * sem_wait() and sem_timedwait() cancellation points or to 455c70dac8SDaniel Eischen * provide a faster userland implementation for non-pshared 465c70dac8SDaniel Eischen * semaphores. 475c70dac8SDaniel Eischen * 485c70dac8SDaniel Eischen * Also, this implementation of semaphores cannot really support 495c70dac8SDaniel Eischen * real pshared semaphores. The sem_t is an allocated object 505c70dac8SDaniel Eischen * and can't be seen by other processes when placed in shared 515c70dac8SDaniel Eischen * memory. It should work across forks as long as the semaphore 525c70dac8SDaniel Eischen * is created before any forks. 535c70dac8SDaniel Eischen * 545c70dac8SDaniel Eischen * The function sem_init() should be overridden by a threads 555c70dac8SDaniel Eischen * library if it wants to provide a different userland version 565c70dac8SDaniel Eischen * of semaphores. The functions sem_wait() and sem_timedwait() 575c70dac8SDaniel Eischen * need to be wrapped to provide cancellation points. The function 585c70dac8SDaniel Eischen * sem_post() may need to be wrapped to be signal-safe. 595c70dac8SDaniel Eischen */ 60e0554a53SJacques Vidrine #include "namespace.h" 61d8f77b45SStefan Farfeleder #include <sys/types.h> 625c70dac8SDaniel Eischen #include <sys/queue.h> 639b0f1823SDavid Xu #include <machine/atomic.h> 64bf4dc877SAlfred Perlstein #include <errno.h> 659b0f1823SDavid Xu #include <sys/umtx.h> 669b0f1823SDavid Xu #include <sys/_semaphore.h> 679b0f1823SDavid Xu #include <limits.h> 68bf4dc877SAlfred Perlstein #include <fcntl.h> 695c70dac8SDaniel Eischen #include <pthread.h> 70bf4dc877SAlfred Perlstein #include <stdarg.h> 715c70dac8SDaniel Eischen #include <stdlib.h> 725c70dac8SDaniel Eischen #include <time.h> 73e0554a53SJacques Vidrine #include "un-namespace.h" 745c70dac8SDaniel Eischen #include "libc_private.h" 75bf4dc877SAlfred Perlstein 769b0f1823SDavid Xu /* 779b0f1823SDavid Xu * Old semaphore definitions. 789b0f1823SDavid Xu */ 799b0f1823SDavid Xu struct sem { 809b0f1823SDavid Xu #define SEM_MAGIC ((u_int32_t) 0x09fa4012) 819b0f1823SDavid Xu u_int32_t magic; 829b0f1823SDavid Xu pthread_mutex_t lock; 839b0f1823SDavid Xu pthread_cond_t gtzero; 849b0f1823SDavid Xu u_int32_t count; 859b0f1823SDavid Xu u_int32_t nwaiters; 869b0f1823SDavid Xu #define SEM_USER (NULL) 879b0f1823SDavid Xu semid_t semid; /* semaphore id if kernel (shared) semaphore */ 889b0f1823SDavid Xu int syssem; /* 1 if kernel (shared) semaphore */ 899b0f1823SDavid Xu LIST_ENTRY(sem) entry; 909b0f1823SDavid Xu struct sem **backpointer; 919b0f1823SDavid Xu }; 929b0f1823SDavid Xu 939b0f1823SDavid Xu typedef struct sem* sem_t; 949b0f1823SDavid Xu 959b0f1823SDavid Xu #define SEM_FAILED ((sem_t *)0) 969b0f1823SDavid Xu #define SEM_VALUE_MAX __INT_MAX 979b0f1823SDavid Xu 989b0f1823SDavid Xu #define SYM_FB10(sym) __CONCAT(sym, _fb10) 999b0f1823SDavid Xu #define WEAK_REF(sym, alias) __weak_reference(sym, alias) 1009b0f1823SDavid Xu #define SYM_COMPAT(sym, impl, ver) __sym_compat(sym, impl, ver) 1019b0f1823SDavid Xu 1029b0f1823SDavid Xu #define FB10_COMPAT(func, sym) \ 1039b0f1823SDavid Xu WEAK_REF(func, SYM_FB10(sym)); \ 1049b0f1823SDavid Xu SYM_COMPAT(sym, SYM_FB10(sym), FBSD_1.0) 1059b0f1823SDavid Xu 106bf4dc877SAlfred Perlstein static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); 107bf4dc877SAlfred Perlstein static void sem_free(sem_t sem); 108bf4dc877SAlfred Perlstein 109dd554467SAntoine Brodin static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(named_sems); 110bf4dc877SAlfred Perlstein static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER; 111bf4dc877SAlfred Perlstein 1129b0f1823SDavid Xu FB10_COMPAT(_libc_sem_init_compat, sem_init); 1139b0f1823SDavid Xu FB10_COMPAT(_libc_sem_destroy_compat, sem_destroy); 1149b0f1823SDavid Xu FB10_COMPAT(_libc_sem_open_compat, sem_open); 1159b0f1823SDavid Xu FB10_COMPAT(_libc_sem_close_compat, sem_close); 1169b0f1823SDavid Xu FB10_COMPAT(_libc_sem_unlink_compat, sem_unlink); 1179b0f1823SDavid Xu FB10_COMPAT(_libc_sem_wait_compat, sem_wait); 1189b0f1823SDavid Xu FB10_COMPAT(_libc_sem_trywait_compat, sem_trywait); 1199b0f1823SDavid Xu FB10_COMPAT(_libc_sem_timedwait_compat, sem_timedwait); 1209b0f1823SDavid Xu FB10_COMPAT(_libc_sem_post_compat, sem_post); 1219b0f1823SDavid Xu FB10_COMPAT(_libc_sem_getvalue_compat, sem_getvalue); 1225c70dac8SDaniel Eischen 1235c70dac8SDaniel Eischen static inline int 1245c70dac8SDaniel Eischen sem_check_validity(sem_t *sem) 1255c70dac8SDaniel Eischen { 1265c70dac8SDaniel Eischen 1275c70dac8SDaniel Eischen if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC)) 1285c70dac8SDaniel Eischen return (0); 1295c70dac8SDaniel Eischen else { 1305c70dac8SDaniel Eischen errno = EINVAL; 1315c70dac8SDaniel Eischen return (-1); 1325c70dac8SDaniel Eischen } 1335c70dac8SDaniel Eischen } 1345c70dac8SDaniel Eischen 135bf4dc877SAlfred Perlstein static void 136bf4dc877SAlfred Perlstein sem_free(sem_t sem) 137bf4dc877SAlfred Perlstein { 138bf4dc877SAlfred Perlstein 139bf4dc877SAlfred Perlstein sem->magic = 0; 140bf4dc877SAlfred Perlstein free(sem); 141bf4dc877SAlfred Perlstein } 142bf4dc877SAlfred Perlstein 143bf4dc877SAlfred Perlstein static sem_t 144bf4dc877SAlfred Perlstein sem_alloc(unsigned int value, semid_t semid, int system_sem) 145bf4dc877SAlfred Perlstein { 146bf4dc877SAlfred Perlstein sem_t sem; 147bf4dc877SAlfred Perlstein 148bf4dc877SAlfred Perlstein if (value > SEM_VALUE_MAX) { 149bf4dc877SAlfred Perlstein errno = EINVAL; 150bf4dc877SAlfred Perlstein return (NULL); 151bf4dc877SAlfred Perlstein } 152bf4dc877SAlfred Perlstein 153bf4dc877SAlfred Perlstein sem = (sem_t)malloc(sizeof(struct sem)); 154bf4dc877SAlfred Perlstein if (sem == NULL) { 155bf4dc877SAlfred Perlstein errno = ENOSPC; 156bf4dc877SAlfred Perlstein return (NULL); 157bf4dc877SAlfred Perlstein } 158bf4dc877SAlfred Perlstein 159bf4dc877SAlfred Perlstein sem->count = (u_int32_t)value; 160bf4dc877SAlfred Perlstein sem->nwaiters = 0; 161bf4dc877SAlfred Perlstein sem->magic = SEM_MAGIC; 162bf4dc877SAlfred Perlstein sem->semid = semid; 163bf4dc877SAlfred Perlstein sem->syssem = system_sem; 164bf4dc877SAlfred Perlstein return (sem); 165bf4dc877SAlfred Perlstein } 166bf4dc877SAlfred Perlstein 167bf4dc877SAlfred Perlstein int 1689b0f1823SDavid Xu _libc_sem_init_compat(sem_t *sem, int pshared, unsigned int value) 169bf4dc877SAlfred Perlstein { 170bf4dc877SAlfred Perlstein semid_t semid; 171bf4dc877SAlfred Perlstein 172bf4dc877SAlfred Perlstein /* 1735c70dac8SDaniel Eischen * We always have to create the kernel semaphore if the 1745c70dac8SDaniel Eischen * threads library isn't present since libc's version of 1755c70dac8SDaniel Eischen * pthread_cond_wait() is just a stub that doesn't really 1765c70dac8SDaniel Eischen * wait. 177bf4dc877SAlfred Perlstein */ 1789b0f1823SDavid Xu semid = (semid_t)SEM_USER; 1799b0f1823SDavid Xu if ((pshared != 0) && ksem_init(&semid, value) != 0) 1805c70dac8SDaniel Eischen return (-1); 181bf4dc877SAlfred Perlstein 1829b0f1823SDavid Xu *sem = sem_alloc(value, semid, pshared); 1835c70dac8SDaniel Eischen if ((*sem) == NULL) { 1849b0f1823SDavid Xu if (pshared != 0) 185bf4dc877SAlfred Perlstein ksem_destroy(semid); 1865c70dac8SDaniel Eischen return (-1); 1875c70dac8SDaniel Eischen } 1885c70dac8SDaniel Eischen return (0); 189bf4dc877SAlfred Perlstein } 190bf4dc877SAlfred Perlstein 191bf4dc877SAlfred Perlstein int 1929b0f1823SDavid Xu _libc_sem_destroy_compat(sem_t *sem) 193bf4dc877SAlfred Perlstein { 194bf4dc877SAlfred Perlstein int retval; 195bf4dc877SAlfred Perlstein 19608a6a888SDaniel Eischen if (sem_check_validity(sem) != 0) 1975c70dac8SDaniel Eischen return (-1); 198bf4dc877SAlfred Perlstein 199bf4dc877SAlfred Perlstein /* 200bf4dc877SAlfred Perlstein * If this is a system semaphore let the kernel track it otherwise 201bf4dc877SAlfred Perlstein * make sure there are no waiters. 202bf4dc877SAlfred Perlstein */ 2035c70dac8SDaniel Eischen if ((*sem)->syssem != 0) 204bf4dc877SAlfred Perlstein retval = ksem_destroy((*sem)->semid); 2055c70dac8SDaniel Eischen else if ((*sem)->nwaiters > 0) { 206bf4dc877SAlfred Perlstein errno = EBUSY; 207bf4dc877SAlfred Perlstein retval = -1; 2085c70dac8SDaniel Eischen } 2095c70dac8SDaniel Eischen else { 2105c70dac8SDaniel Eischen retval = 0; 2115c70dac8SDaniel Eischen (*sem)->magic = 0; 212bf4dc877SAlfred Perlstein } 213bf4dc877SAlfred Perlstein 2149b0f1823SDavid Xu if (retval == 0) 215bf4dc877SAlfred Perlstein sem_free(*sem); 2165c70dac8SDaniel Eischen return (retval); 217bf4dc877SAlfred Perlstein } 218bf4dc877SAlfred Perlstein 219bf4dc877SAlfred Perlstein sem_t * 2209b0f1823SDavid Xu _libc_sem_open_compat(const char *name, int oflag, ...) 221bf4dc877SAlfred Perlstein { 222bf4dc877SAlfred Perlstein sem_t *sem; 223bf4dc877SAlfred Perlstein sem_t s; 224bf4dc877SAlfred Perlstein semid_t semid; 225bf4dc877SAlfred Perlstein mode_t mode; 226bf4dc877SAlfred Perlstein unsigned int value; 227bf4dc877SAlfred Perlstein 228bf4dc877SAlfred Perlstein mode = 0; 229bf4dc877SAlfred Perlstein value = 0; 230bf4dc877SAlfred Perlstein 231bf4dc877SAlfred Perlstein if ((oflag & O_CREAT) != 0) { 232bf4dc877SAlfred Perlstein va_list ap; 233bf4dc877SAlfred Perlstein 234bf4dc877SAlfred Perlstein va_start(ap, oflag); 235bf4dc877SAlfred Perlstein mode = va_arg(ap, int); 236bf4dc877SAlfred Perlstein value = va_arg(ap, unsigned int); 237bf4dc877SAlfred Perlstein va_end(ap); 238bf4dc877SAlfred Perlstein } 239bf4dc877SAlfred Perlstein /* 240bf4dc877SAlfred Perlstein * we can be lazy and let the kernel handle the "oflag", 241bf4dc877SAlfred Perlstein * we'll just merge duplicate IDs into our list. 242bf4dc877SAlfred Perlstein */ 243bf4dc877SAlfred Perlstein if (ksem_open(&semid, name, oflag, mode, value) == -1) 244bf4dc877SAlfred Perlstein return (SEM_FAILED); 245bf4dc877SAlfred Perlstein /* 246bf4dc877SAlfred Perlstein * search for a duplicate ID, we must return the same sem_t * 247bf4dc877SAlfred Perlstein * if we locate one. 248bf4dc877SAlfred Perlstein */ 249bf4dc877SAlfred Perlstein _pthread_mutex_lock(&named_sems_mtx); 250bf4dc877SAlfred Perlstein LIST_FOREACH(s, &named_sems, entry) { 251bf4dc877SAlfred Perlstein if (s->semid == semid) { 2525c70dac8SDaniel Eischen sem = s->backpointer; 253bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 2545c70dac8SDaniel Eischen return (sem); 255bf4dc877SAlfred Perlstein } 256bf4dc877SAlfred Perlstein } 257bf4dc877SAlfred Perlstein sem = (sem_t *)malloc(sizeof(*sem)); 258bf4dc877SAlfred Perlstein if (sem == NULL) 259bf4dc877SAlfred Perlstein goto err; 260bf4dc877SAlfred Perlstein *sem = sem_alloc(value, semid, 1); 261bf4dc877SAlfred Perlstein if ((*sem) == NULL) 262bf4dc877SAlfred Perlstein goto err; 263a91b25dcSTim J. Robbins LIST_INSERT_HEAD(&named_sems, *sem, entry); 264bf4dc877SAlfred Perlstein (*sem)->backpointer = sem; 265a91b25dcSTim J. Robbins _pthread_mutex_unlock(&named_sems_mtx); 266bf4dc877SAlfred Perlstein return (sem); 267bf4dc877SAlfred Perlstein err: 268bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 269bf4dc877SAlfred Perlstein ksem_close(semid); 270bf4dc877SAlfred Perlstein if (sem != NULL) { 271bf4dc877SAlfred Perlstein if (*sem != NULL) 272bf4dc877SAlfred Perlstein sem_free(*sem); 273bf4dc877SAlfred Perlstein else 274bf4dc877SAlfred Perlstein errno = ENOSPC; 275bf4dc877SAlfred Perlstein free(sem); 276bf4dc877SAlfred Perlstein } else { 277bf4dc877SAlfred Perlstein errno = ENOSPC; 278bf4dc877SAlfred Perlstein } 279bf4dc877SAlfred Perlstein return (SEM_FAILED); 280bf4dc877SAlfred Perlstein } 281bf4dc877SAlfred Perlstein 282bf4dc877SAlfred Perlstein int 2839b0f1823SDavid Xu _libc_sem_close_compat(sem_t *sem) 284bf4dc877SAlfred Perlstein { 285bf4dc877SAlfred Perlstein 2865c70dac8SDaniel Eischen if (sem_check_validity(sem) != 0) 2875c70dac8SDaniel Eischen return (-1); 2885c70dac8SDaniel Eischen 289bf4dc877SAlfred Perlstein if ((*sem)->syssem == 0) { 290bf4dc877SAlfred Perlstein errno = EINVAL; 291bf4dc877SAlfred Perlstein return (-1); 292bf4dc877SAlfred Perlstein } 2935c70dac8SDaniel Eischen 294bf4dc877SAlfred Perlstein _pthread_mutex_lock(&named_sems_mtx); 2955c70dac8SDaniel Eischen if (ksem_close((*sem)->semid) != 0) { 296bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 297bf4dc877SAlfred Perlstein return (-1); 298bf4dc877SAlfred Perlstein } 299bf4dc877SAlfred Perlstein LIST_REMOVE((*sem), entry); 300bf4dc877SAlfred Perlstein _pthread_mutex_unlock(&named_sems_mtx); 301bf4dc877SAlfred Perlstein sem_free(*sem); 3025c70dac8SDaniel Eischen *sem = NULL; 303bf4dc877SAlfred Perlstein free(sem); 304bf4dc877SAlfred Perlstein return (0); 305bf4dc877SAlfred Perlstein } 306bf4dc877SAlfred Perlstein 307bf4dc877SAlfred Perlstein int 3089b0f1823SDavid Xu _libc_sem_unlink_compat(const char *name) 309bf4dc877SAlfred Perlstein { 310bf4dc877SAlfred Perlstein 311bf4dc877SAlfred Perlstein return (ksem_unlink(name)); 312bf4dc877SAlfred Perlstein } 313bf4dc877SAlfred Perlstein 3149b0f1823SDavid Xu static int 3159b0f1823SDavid Xu enable_async_cancel(void) 316bf4dc877SAlfred Perlstein { 3179b0f1823SDavid Xu int old; 318bf4dc877SAlfred Perlstein 3199b0f1823SDavid Xu _pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old); 3209b0f1823SDavid Xu return (old); 3219b0f1823SDavid Xu } 3229b0f1823SDavid Xu 3239b0f1823SDavid Xu static void 3249b0f1823SDavid Xu restore_async_cancel(int val) 3259b0f1823SDavid Xu { 3269b0f1823SDavid Xu _pthread_setcanceltype(val, NULL); 3279b0f1823SDavid Xu } 3289b0f1823SDavid Xu 3299b0f1823SDavid Xu static int 3309b0f1823SDavid Xu _umtx_wait_uint(volatile unsigned *mtx, unsigned id, const struct timespec *timeout) 3319b0f1823SDavid Xu { 3329b0f1823SDavid Xu if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 && 3339b0f1823SDavid Xu timeout->tv_nsec <= 0))) { 3349b0f1823SDavid Xu errno = ETIMEDOUT; 3355c70dac8SDaniel Eischen return (-1); 3369b0f1823SDavid Xu } 3379b0f1823SDavid Xu return _umtx_op(__DEVOLATILE(void *, mtx), 3389b0f1823SDavid Xu UMTX_OP_WAIT_UINT_PRIVATE, id, NULL, __DECONST(void*, timeout)); 3399b0f1823SDavid Xu } 340bf4dc877SAlfred Perlstein 3419b0f1823SDavid Xu static int 3429b0f1823SDavid Xu _umtx_wake(volatile void *mtx) 3439b0f1823SDavid Xu { 3449b0f1823SDavid Xu return _umtx_op(__DEVOLATILE(void *, mtx), UMTX_OP_WAKE_PRIVATE, 3459b0f1823SDavid Xu 1, NULL, NULL); 3469b0f1823SDavid Xu } 3479b0f1823SDavid Xu 3489b0f1823SDavid Xu #define TIMESPEC_SUB(dst, src, val) \ 3499b0f1823SDavid Xu do { \ 3509b0f1823SDavid Xu (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \ 3519b0f1823SDavid Xu (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \ 3529b0f1823SDavid Xu if ((dst)->tv_nsec < 0) { \ 3539b0f1823SDavid Xu (dst)->tv_sec--; \ 3549b0f1823SDavid Xu (dst)->tv_nsec += 1000000000; \ 3559b0f1823SDavid Xu } \ 3569b0f1823SDavid Xu } while (0) 3579b0f1823SDavid Xu 3589b0f1823SDavid Xu 3599b0f1823SDavid Xu static void 3609b0f1823SDavid Xu sem_cancel_handler(void *arg) 3619b0f1823SDavid Xu { 3629b0f1823SDavid Xu sem_t *sem = arg; 3639b0f1823SDavid Xu 3649b0f1823SDavid Xu atomic_add_int(&(*sem)->nwaiters, -1); 3659b0f1823SDavid Xu if ((*sem)->nwaiters && (*sem)->count) 3669b0f1823SDavid Xu _umtx_wake(&(*sem)->count); 367bf4dc877SAlfred Perlstein } 368bf4dc877SAlfred Perlstein 369bf4dc877SAlfred Perlstein int 3709b0f1823SDavid Xu _libc_sem_timedwait_compat(sem_t * __restrict sem, 3719b0f1823SDavid Xu const struct timespec * __restrict abstime) 372bf4dc877SAlfred Perlstein { 3739b0f1823SDavid Xu struct timespec ts, ts2; 3749b0f1823SDavid Xu int val, retval, saved_cancel; 375bf4dc877SAlfred Perlstein 3765c70dac8SDaniel Eischen if (sem_check_validity(sem) != 0) 3775c70dac8SDaniel Eischen return (-1); 378bf4dc877SAlfred Perlstein 3799b0f1823SDavid Xu if ((*sem)->syssem != 0) { 3809b0f1823SDavid Xu saved_cancel = enable_async_cancel(); 3819b0f1823SDavid Xu retval = ksem_wait((*sem)->semid); 3829b0f1823SDavid Xu restore_async_cancel(saved_cancel); 3839b0f1823SDavid Xu return (retval); 3849b0f1823SDavid Xu } 3859b0f1823SDavid Xu 386903f2e50SDaniel Eischen retval = 0; 3879b0f1823SDavid Xu _pthread_testcancel(); 3889b0f1823SDavid Xu for (;;) { 3899b0f1823SDavid Xu while ((val = (*sem)->count) > 0) { 3909b0f1823SDavid Xu if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) 3919b0f1823SDavid Xu return (0); 392903f2e50SDaniel Eischen } 3939b0f1823SDavid Xu if (retval) 3949b0f1823SDavid Xu break; 3959b0f1823SDavid Xu if (abstime) { 3969b0f1823SDavid Xu if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) { 3979b0f1823SDavid Xu errno = EINVAL; 3989b0f1823SDavid Xu return (-1); 3999b0f1823SDavid Xu } 4009b0f1823SDavid Xu clock_gettime(CLOCK_REALTIME, &ts); 4019b0f1823SDavid Xu TIMESPEC_SUB(&ts2, abstime, &ts); 4029b0f1823SDavid Xu } 4039b0f1823SDavid Xu atomic_add_int(&(*sem)->nwaiters, 1); 4049b0f1823SDavid Xu pthread_cleanup_push(sem_cancel_handler, sem); 4059b0f1823SDavid Xu saved_cancel = enable_async_cancel(); 4069b0f1823SDavid Xu retval = _umtx_wait_uint(&(*sem)->count, 0, abstime ? &ts2 : NULL); 4079b0f1823SDavid Xu restore_async_cancel(saved_cancel); 4089b0f1823SDavid Xu pthread_cleanup_pop(0); 4099b0f1823SDavid Xu atomic_add_int(&(*sem)->nwaiters, -1); 410903f2e50SDaniel Eischen } 411903f2e50SDaniel Eischen return (retval); 412bf4dc877SAlfred Perlstein } 413bf4dc877SAlfred Perlstein 414bf4dc877SAlfred Perlstein int 4159b0f1823SDavid Xu _libc_sem_wait_compat(sem_t *sem) 416bf4dc877SAlfred Perlstein { 4179b0f1823SDavid Xu return _libc_sem_timedwait_compat(sem, NULL); 418bf4dc877SAlfred Perlstein } 419bf4dc877SAlfred Perlstein 420bf4dc877SAlfred Perlstein int 4219b0f1823SDavid Xu _libc_sem_trywait_compat(sem_t *sem) 4229b0f1823SDavid Xu { 4239b0f1823SDavid Xu int val; 4249b0f1823SDavid Xu 4259b0f1823SDavid Xu if (sem_check_validity(sem) != 0) 4269b0f1823SDavid Xu return (-1); 4279b0f1823SDavid Xu 4289b0f1823SDavid Xu if ((*sem)->syssem != 0) 4299b0f1823SDavid Xu return ksem_trywait((*sem)->semid); 4309b0f1823SDavid Xu 4319b0f1823SDavid Xu while ((val = (*sem)->count) > 0) { 4329b0f1823SDavid Xu if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) 4339b0f1823SDavid Xu return (0); 4349b0f1823SDavid Xu } 4359b0f1823SDavid Xu errno = EAGAIN; 4369b0f1823SDavid Xu return (-1); 4379b0f1823SDavid Xu } 4389b0f1823SDavid Xu 4399b0f1823SDavid Xu int 4409b0f1823SDavid Xu _libc_sem_post_compat(sem_t *sem) 4415c70dac8SDaniel Eischen { 4425c70dac8SDaniel Eischen 4435c70dac8SDaniel Eischen if (sem_check_validity(sem) != 0) 4445c70dac8SDaniel Eischen return (-1); 4455c70dac8SDaniel Eischen 4469b0f1823SDavid Xu if ((*sem)->syssem != 0) 4479b0f1823SDavid Xu return ksem_post((*sem)->semid); 4489b0f1823SDavid Xu 4499b0f1823SDavid Xu atomic_add_rel_int(&(*sem)->count, 1); 4509b0f1823SDavid Xu 4519b0f1823SDavid Xu if ((*sem)->nwaiters) 4529b0f1823SDavid Xu return _umtx_wake(&(*sem)->count); 4539b0f1823SDavid Xu return (0); 4545c70dac8SDaniel Eischen } 4555c70dac8SDaniel Eischen 4565c70dac8SDaniel Eischen int 4579b0f1823SDavid Xu _libc_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval) 458bf4dc877SAlfred Perlstein { 459bf4dc877SAlfred Perlstein int retval; 460bf4dc877SAlfred Perlstein 4615c70dac8SDaniel Eischen if (sem_check_validity(sem) != 0) 4625c70dac8SDaniel Eischen return (-1); 463bf4dc877SAlfred Perlstein 4645c70dac8SDaniel Eischen if ((*sem)->syssem != 0) 465bf4dc877SAlfred Perlstein retval = ksem_getvalue((*sem)->semid, sval); 4665c70dac8SDaniel Eischen else { 467bf4dc877SAlfred Perlstein *sval = (int)(*sem)->count; 468bf4dc877SAlfred Perlstein retval = 0; 4695c70dac8SDaniel Eischen } 4705c70dac8SDaniel Eischen return (retval); 471bf4dc877SAlfred Perlstein } 472