1d915a14eSPedro F. Giffuni /*- 2d915a14eSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3d915a14eSPedro F. Giffuni * 49b0f1823SDavid Xu * Copyright (C) 2010 David Xu <davidxu@freebsd.org>. 59b0f1823SDavid Xu * All rights reserved. 69b0f1823SDavid Xu * 79b0f1823SDavid Xu * Redistribution and use in source and binary forms, with or without 89b0f1823SDavid Xu * modification, are permitted provided that the following conditions 99b0f1823SDavid Xu * are met: 109b0f1823SDavid Xu * 1. Redistributions of source code must retain the above copyright 119b0f1823SDavid Xu * notice(s), this list of conditions and the following disclaimer as 129b0f1823SDavid Xu * the first lines of this file unmodified other than the possible 139b0f1823SDavid Xu * addition of one or more copyright notices. 149b0f1823SDavid Xu * 2. Redistributions in binary form must reproduce the above copyright 159b0f1823SDavid Xu * notice(s), this list of conditions and the following disclaimer in 169b0f1823SDavid Xu * the documentation and/or other materials provided with the 179b0f1823SDavid Xu * distribution. 189b0f1823SDavid Xu * 199b0f1823SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 209b0f1823SDavid Xu * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 219b0f1823SDavid Xu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 229b0f1823SDavid Xu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 239b0f1823SDavid Xu * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 249b0f1823SDavid Xu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 259b0f1823SDavid Xu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 269b0f1823SDavid Xu * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 279b0f1823SDavid Xu * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 289b0f1823SDavid Xu * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 299b0f1823SDavid Xu * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 309b0f1823SDavid Xu * 319b0f1823SDavid Xu * $FreeBSD$ 329b0f1823SDavid Xu */ 339b0f1823SDavid Xu 349b0f1823SDavid Xu #include "namespace.h" 359b0f1823SDavid Xu #include <sys/types.h> 369b0f1823SDavid Xu #include <sys/queue.h> 379b0f1823SDavid Xu #include <sys/mman.h> 389b0f1823SDavid Xu #include <sys/stat.h> 399b0f1823SDavid Xu #include <errno.h> 409b0f1823SDavid Xu #include <machine/atomic.h> 419b0f1823SDavid Xu #include <sys/umtx.h> 429b0f1823SDavid Xu #include <limits.h> 439b0f1823SDavid Xu #include <fcntl.h> 449b0f1823SDavid Xu #include <pthread.h> 459b0f1823SDavid Xu #include <stdarg.h> 46e6a183a4SKonstantin Belousov #include <stdbool.h> 479b0f1823SDavid Xu #include <stdlib.h> 489b0f1823SDavid Xu #include <string.h> 499b0f1823SDavid Xu #include <time.h> 509b0f1823SDavid Xu #include <semaphore.h> 519b0f1823SDavid Xu #include <unistd.h> 529b0f1823SDavid Xu #include "un-namespace.h" 53f4213b90SDavid Xu #include "libc_private.h" 549b0f1823SDavid Xu 55523a738fSDavid Xu __weak_reference(_sem_close, sem_close); 56523a738fSDavid Xu __weak_reference(_sem_destroy, sem_destroy); 57523a738fSDavid Xu __weak_reference(_sem_getvalue, sem_getvalue); 58523a738fSDavid Xu __weak_reference(_sem_init, sem_init); 59523a738fSDavid Xu __weak_reference(_sem_open, sem_open); 60523a738fSDavid Xu __weak_reference(_sem_post, sem_post); 61523a738fSDavid Xu __weak_reference(_sem_timedwait, sem_timedwait); 62b215ceaaSEric van Gyzen __weak_reference(_sem_clockwait_np, sem_clockwait_np); 63523a738fSDavid Xu __weak_reference(_sem_trywait, sem_trywait); 64523a738fSDavid Xu __weak_reference(_sem_unlink, sem_unlink); 65523a738fSDavid Xu __weak_reference(_sem_wait, sem_wait); 669b0f1823SDavid Xu 679b0f1823SDavid Xu #define SEM_PREFIX "/tmp/SEMD" 6853e1ffbbSJohn Baldwin #define SEM_MAGIC ((u_int32_t)0x73656d32) 6953e1ffbbSJohn Baldwin 7053e1ffbbSJohn Baldwin _Static_assert(SEM_VALUE_MAX <= USEM_MAX_COUNT, "SEM_VALUE_MAX too large"); 719b0f1823SDavid Xu 729b0f1823SDavid Xu struct sem_nameinfo { 739b0f1823SDavid Xu int open_count; 749b0f1823SDavid Xu char *name; 75ca5e4fe9SKonstantin Belousov dev_t dev; 76ca5e4fe9SKonstantin Belousov ino_t ino; 779b0f1823SDavid Xu sem_t *sem; 789b0f1823SDavid Xu LIST_ENTRY(sem_nameinfo) next; 799b0f1823SDavid Xu }; 809b0f1823SDavid Xu 819b0f1823SDavid Xu static pthread_once_t once = PTHREAD_ONCE_INIT; 829b0f1823SDavid Xu static pthread_mutex_t sem_llock; 839b0f1823SDavid Xu static LIST_HEAD(, sem_nameinfo) sem_list = LIST_HEAD_INITIALIZER(sem_list); 849b0f1823SDavid Xu 859b0f1823SDavid Xu static void 863a137162SKonstantin Belousov sem_prefork(void) 879b0f1823SDavid Xu { 889b0f1823SDavid Xu 899b0f1823SDavid Xu _pthread_mutex_lock(&sem_llock); 909b0f1823SDavid Xu } 919b0f1823SDavid Xu 929b0f1823SDavid Xu static void 933a137162SKonstantin Belousov sem_postfork(void) 949b0f1823SDavid Xu { 953a137162SKonstantin Belousov 969b0f1823SDavid Xu _pthread_mutex_unlock(&sem_llock); 979b0f1823SDavid Xu } 989b0f1823SDavid Xu 999b0f1823SDavid Xu static void 1003a137162SKonstantin Belousov sem_child_postfork(void) 1019b0f1823SDavid Xu { 1023a137162SKonstantin Belousov 1039b0f1823SDavid Xu _pthread_mutex_unlock(&sem_llock); 1049b0f1823SDavid Xu } 1059b0f1823SDavid Xu 1069b0f1823SDavid Xu static void 1079b0f1823SDavid Xu sem_module_init(void) 1089b0f1823SDavid Xu { 1099b0f1823SDavid Xu 110f7a6f6a2SKonstantin Belousov _pthread_mutex_init(&sem_llock, NULL); 1119b0f1823SDavid Xu _pthread_atfork(sem_prefork, sem_postfork, sem_child_postfork); 1129b0f1823SDavid Xu } 1139b0f1823SDavid Xu 1149b0f1823SDavid Xu static inline int 1159b0f1823SDavid Xu sem_check_validity(sem_t *sem) 1169b0f1823SDavid Xu { 1179b0f1823SDavid Xu 1184e2158bfSDavid Xu if (sem->_magic == SEM_MAGIC) 1199b0f1823SDavid Xu return (0); 1209b0f1823SDavid Xu errno = EINVAL; 1219b0f1823SDavid Xu return (-1); 1229b0f1823SDavid Xu } 1239b0f1823SDavid Xu 1249b0f1823SDavid Xu int 125523a738fSDavid Xu _sem_init(sem_t *sem, int pshared, unsigned int value) 1269b0f1823SDavid Xu { 1279b0f1823SDavid Xu 1289b0f1823SDavid Xu if (value > SEM_VALUE_MAX) { 1299b0f1823SDavid Xu errno = EINVAL; 1309b0f1823SDavid Xu return (-1); 1319b0f1823SDavid Xu } 1329b0f1823SDavid Xu 1339b0f1823SDavid Xu bzero(sem, sizeof(sem_t)); 1349b0f1823SDavid Xu sem->_magic = SEM_MAGIC; 1359b0f1823SDavid Xu sem->_kern._count = (u_int32_t)value; 1364e2158bfSDavid Xu sem->_kern._flags = pshared ? USYNC_PROCESS_SHARED : 0; 1379b0f1823SDavid Xu return (0); 1389b0f1823SDavid Xu } 1399b0f1823SDavid Xu 1409b0f1823SDavid Xu sem_t * 141523a738fSDavid Xu _sem_open(const char *name, int flags, ...) 1429b0f1823SDavid Xu { 1439b0f1823SDavid Xu char path[PATH_MAX]; 1449b0f1823SDavid Xu struct stat sb; 1459b0f1823SDavid Xu va_list ap; 1463a137162SKonstantin Belousov struct sem_nameinfo *ni; 1473a137162SKonstantin Belousov sem_t *sem, tmp; 1483a137162SKonstantin Belousov int errsave, fd, len, mode, value; 1493a137162SKonstantin Belousov 1503a137162SKonstantin Belousov ni = NULL; 1513a137162SKonstantin Belousov sem = NULL; 1523a137162SKonstantin Belousov fd = -1; 1533a137162SKonstantin Belousov value = 0; 1549b0f1823SDavid Xu 1559b0f1823SDavid Xu if (name[0] != '/') { 1569b0f1823SDavid Xu errno = EINVAL; 15741e16053SDavid Xu return (SEM_FAILED); 1589b0f1823SDavid Xu } 1599b0f1823SDavid Xu name++; 160ca5e4fe9SKonstantin Belousov strcpy(path, SEM_PREFIX); 161ca5e4fe9SKonstantin Belousov if (strlcat(path, name, sizeof(path)) >= sizeof(path)) { 162ca5e4fe9SKonstantin Belousov errno = ENAMETOOLONG; 163ca5e4fe9SKonstantin Belousov return (SEM_FAILED); 164ca5e4fe9SKonstantin Belousov } 1659b0f1823SDavid Xu if (flags & ~(O_CREAT|O_EXCL)) { 1669b0f1823SDavid Xu errno = EINVAL; 16741e16053SDavid Xu return (SEM_FAILED); 1689b0f1823SDavid Xu } 169ca5e4fe9SKonstantin Belousov if ((flags & O_CREAT) != 0) { 1709b0f1823SDavid Xu va_start(ap, flags); 1719b0f1823SDavid Xu mode = va_arg(ap, int); 172323d80a0SDavid Xu value = va_arg(ap, int); 1739b0f1823SDavid Xu va_end(ap); 1749b0f1823SDavid Xu } 175ca5e4fe9SKonstantin Belousov fd = -1; 176ca5e4fe9SKonstantin Belousov _pthread_once(&once, sem_module_init); 177ca5e4fe9SKonstantin Belousov 178ca5e4fe9SKonstantin Belousov _pthread_mutex_lock(&sem_llock); 179ca5e4fe9SKonstantin Belousov LIST_FOREACH(ni, &sem_list, next) { 180ca5e4fe9SKonstantin Belousov if (ni->name != NULL && strcmp(name, ni->name) == 0) { 181ca5e4fe9SKonstantin Belousov fd = _open(path, flags | O_RDWR | O_CLOEXEC | 182ca5e4fe9SKonstantin Belousov O_EXLOCK, mode); 183afa04e41SJilles Tjoelker if (fd == -1 || _fstat(fd, &sb) == -1) { 184afa04e41SJilles Tjoelker ni = NULL; 185ca5e4fe9SKonstantin Belousov goto error; 186afa04e41SJilles Tjoelker } 187ca5e4fe9SKonstantin Belousov if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | 188ca5e4fe9SKonstantin Belousov O_EXCL) || ni->dev != sb.st_dev || 189ca5e4fe9SKonstantin Belousov ni->ino != sb.st_ino) { 190ca5e4fe9SKonstantin Belousov ni->name = NULL; 191ca5e4fe9SKonstantin Belousov ni = NULL; 192ca5e4fe9SKonstantin Belousov break; 193ca5e4fe9SKonstantin Belousov } 194ca5e4fe9SKonstantin Belousov ni->open_count++; 195ca5e4fe9SKonstantin Belousov sem = ni->sem; 196ca5e4fe9SKonstantin Belousov _pthread_mutex_unlock(&sem_llock); 197ca5e4fe9SKonstantin Belousov _close(fd); 198ca5e4fe9SKonstantin Belousov return (sem); 199ca5e4fe9SKonstantin Belousov } 200ca5e4fe9SKonstantin Belousov } 2019b0f1823SDavid Xu 2029b0f1823SDavid Xu len = sizeof(*ni) + strlen(name) + 1; 2039b0f1823SDavid Xu ni = (struct sem_nameinfo *)malloc(len); 2049b0f1823SDavid Xu if (ni == NULL) { 2059b0f1823SDavid Xu errno = ENOSPC; 2069b0f1823SDavid Xu goto error; 2079b0f1823SDavid Xu } 2089b0f1823SDavid Xu 2099b0f1823SDavid Xu ni->name = (char *)(ni+1); 2109b0f1823SDavid Xu strcpy(ni->name, name); 2119b0f1823SDavid Xu 212ca5e4fe9SKonstantin Belousov if (fd == -1) { 213ca5e4fe9SKonstantin Belousov fd = _open(path, flags | O_RDWR | O_CLOEXEC | O_EXLOCK, mode); 214ca5e4fe9SKonstantin Belousov if (fd == -1 || _fstat(fd, &sb) == -1) 2159b0f1823SDavid Xu goto error; 2169b0f1823SDavid Xu } 2179b0f1823SDavid Xu if (sb.st_size < sizeof(sem_t)) { 2189b0f1823SDavid Xu tmp._magic = SEM_MAGIC; 219323d80a0SDavid Xu tmp._kern._count = value; 2204e2158bfSDavid Xu tmp._kern._flags = USYNC_PROCESS_SHARED | SEM_NAMED; 221a9c09aeeSDavid Xu if (_write(fd, &tmp, sizeof(tmp)) != sizeof(tmp)) 2229b0f1823SDavid Xu goto error; 2239b0f1823SDavid Xu } 2249b0f1823SDavid Xu flock(fd, LOCK_UN); 2253a137162SKonstantin Belousov sem = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, 2269b0f1823SDavid Xu MAP_SHARED | MAP_NOSYNC, fd, 0); 2279b0f1823SDavid Xu if (sem == MAP_FAILED) { 2289b0f1823SDavid Xu sem = NULL; 2299b0f1823SDavid Xu if (errno == ENOMEM) 2309b0f1823SDavid Xu errno = ENOSPC; 2319b0f1823SDavid Xu goto error; 2329b0f1823SDavid Xu } 2339b0f1823SDavid Xu if (sem->_magic != SEM_MAGIC) { 2349b0f1823SDavid Xu errno = EINVAL; 2359b0f1823SDavid Xu goto error; 2369b0f1823SDavid Xu } 2379b0f1823SDavid Xu ni->open_count = 1; 2389b0f1823SDavid Xu ni->sem = sem; 239ca5e4fe9SKonstantin Belousov ni->dev = sb.st_dev; 240ca5e4fe9SKonstantin Belousov ni->ino = sb.st_ino; 2419b0f1823SDavid Xu LIST_INSERT_HEAD(&sem_list, ni, next); 2429b0f1823SDavid Xu _close(fd); 24317001e0bSDavid Xu _pthread_mutex_unlock(&sem_llock); 2449b0f1823SDavid Xu return (sem); 2459b0f1823SDavid Xu 2469b0f1823SDavid Xu error: 2474c1c132bSDavid Xu errsave = errno; 2489b0f1823SDavid Xu if (fd != -1) 2499b0f1823SDavid Xu _close(fd); 2509b0f1823SDavid Xu if (sem != NULL) 2519b0f1823SDavid Xu munmap(sem, sizeof(sem_t)); 2529b0f1823SDavid Xu free(ni); 25317001e0bSDavid Xu _pthread_mutex_unlock(&sem_llock); 2544c1c132bSDavid Xu errno = errsave; 2559b0f1823SDavid Xu return (SEM_FAILED); 2569b0f1823SDavid Xu } 2579b0f1823SDavid Xu 2589b0f1823SDavid Xu int 259523a738fSDavid Xu _sem_close(sem_t *sem) 2609b0f1823SDavid Xu { 2619b0f1823SDavid Xu struct sem_nameinfo *ni; 262e6a183a4SKonstantin Belousov bool last; 2639b0f1823SDavid Xu 2649b0f1823SDavid Xu if (sem_check_validity(sem) != 0) 2659b0f1823SDavid Xu return (-1); 2669b0f1823SDavid Xu 2679b0f1823SDavid Xu if (!(sem->_kern._flags & SEM_NAMED)) { 2689b0f1823SDavid Xu errno = EINVAL; 2699b0f1823SDavid Xu return (-1); 2709b0f1823SDavid Xu } 2719b0f1823SDavid Xu 272764ce7ceSDavid Xu _pthread_once(&once, sem_module_init); 273764ce7ceSDavid Xu 2749b0f1823SDavid Xu _pthread_mutex_lock(&sem_llock); 2759b0f1823SDavid Xu LIST_FOREACH(ni, &sem_list, next) { 2769b0f1823SDavid Xu if (sem == ni->sem) { 277e6a183a4SKonstantin Belousov last = --ni->open_count == 0; 278e6a183a4SKonstantin Belousov if (last) 2799b0f1823SDavid Xu LIST_REMOVE(ni, next); 2809b0f1823SDavid Xu _pthread_mutex_unlock(&sem_llock); 281e6a183a4SKonstantin Belousov if (last) { 2829b0f1823SDavid Xu munmap(sem, sizeof(*sem)); 2839b0f1823SDavid Xu free(ni); 284e6a183a4SKonstantin Belousov } 2859b0f1823SDavid Xu return (0); 2869b0f1823SDavid Xu } 287e6a183a4SKonstantin Belousov } 2889b0f1823SDavid Xu _pthread_mutex_unlock(&sem_llock); 28941e16053SDavid Xu errno = EINVAL; 2909b0f1823SDavid Xu return (-1); 2919b0f1823SDavid Xu } 2929b0f1823SDavid Xu 2939b0f1823SDavid Xu int 294523a738fSDavid Xu _sem_unlink(const char *name) 2959b0f1823SDavid Xu { 2969b0f1823SDavid Xu char path[PATH_MAX]; 2979b0f1823SDavid Xu 2989b0f1823SDavid Xu if (name[0] != '/') { 2999b0f1823SDavid Xu errno = ENOENT; 3009b0f1823SDavid Xu return -1; 3019b0f1823SDavid Xu } 3029b0f1823SDavid Xu name++; 3039b0f1823SDavid Xu strcpy(path, SEM_PREFIX); 3049b0f1823SDavid Xu if (strlcat(path, name, sizeof(path)) >= sizeof(path)) { 3059b0f1823SDavid Xu errno = ENAMETOOLONG; 3069b0f1823SDavid Xu return (-1); 3079b0f1823SDavid Xu } 3089b6224b7SKonstantin Belousov 3099b6224b7SKonstantin Belousov return (unlink(path)); 3109b0f1823SDavid Xu } 3119b0f1823SDavid Xu 3129b0f1823SDavid Xu int 313523a738fSDavid Xu _sem_destroy(sem_t *sem) 3149b0f1823SDavid Xu { 3159b0f1823SDavid Xu 3169b0f1823SDavid Xu if (sem_check_validity(sem) != 0) 3179b0f1823SDavid Xu return (-1); 3189b0f1823SDavid Xu 3199b0f1823SDavid Xu if (sem->_kern._flags & SEM_NAMED) { 3209b0f1823SDavid Xu errno = EINVAL; 3219b0f1823SDavid Xu return (-1); 3229b0f1823SDavid Xu } 3239b0f1823SDavid Xu sem->_magic = 0; 3249b0f1823SDavid Xu return (0); 3259b0f1823SDavid Xu } 3269b0f1823SDavid Xu 3279b0f1823SDavid Xu int 328523a738fSDavid Xu _sem_getvalue(sem_t * __restrict sem, int * __restrict sval) 3299b0f1823SDavid Xu { 3309b0f1823SDavid Xu 3319b0f1823SDavid Xu if (sem_check_validity(sem) != 0) 3329b0f1823SDavid Xu return (-1); 3339b0f1823SDavid Xu 33453e1ffbbSJohn Baldwin *sval = (int)USEM_COUNT(sem->_kern._count); 3359b0f1823SDavid Xu return (0); 3369b0f1823SDavid Xu } 3379b0f1823SDavid Xu 338d802aa25SDavid Xu static __inline int 33953e1ffbbSJohn Baldwin usem_wake(struct _usem2 *sem) 3404e2158bfSDavid Xu { 3413a137162SKonstantin Belousov 3423a137162SKonstantin Belousov return (_umtx_op(sem, UMTX_OP_SEM2_WAKE, 0, NULL, NULL)); 3434e2158bfSDavid Xu } 3444e2158bfSDavid Xu 3454e2158bfSDavid Xu static __inline int 346b215ceaaSEric van Gyzen usem_wait(struct _usem2 *sem, clockid_t clock_id, int flags, 347b215ceaaSEric van Gyzen const struct timespec *rqtp, struct timespec *rmtp) 3489b0f1823SDavid Xu { 349b215ceaaSEric van Gyzen struct { 350b215ceaaSEric van Gyzen struct _umtx_time timeout; 351b215ceaaSEric van Gyzen struct timespec remain; 352b215ceaaSEric van Gyzen } tms; 353b215ceaaSEric van Gyzen void *tm_p; 354df1f1baeSDavid Xu size_t tm_size; 355b215ceaaSEric van Gyzen int retval; 356df1f1baeSDavid Xu 357b215ceaaSEric van Gyzen if (rqtp == NULL) { 358df1f1baeSDavid Xu tm_p = NULL; 359df1f1baeSDavid Xu tm_size = 0; 360df1f1baeSDavid Xu } else { 361b215ceaaSEric van Gyzen tms.timeout._clockid = clock_id; 362b215ceaaSEric van Gyzen tms.timeout._flags = (flags & TIMER_ABSTIME) ? UMTX_ABSTIME : 0; 363b215ceaaSEric van Gyzen tms.timeout._timeout = *rqtp; 364b215ceaaSEric van Gyzen tm_p = &tms; 365b215ceaaSEric van Gyzen tm_size = sizeof(tms); 3669b0f1823SDavid Xu } 367b215ceaaSEric van Gyzen retval = _umtx_op(sem, UMTX_OP_SEM2_WAIT, 0, (void *)tm_size, tm_p); 368b215ceaaSEric van Gyzen if (retval == -1 && errno == EINTR && (flags & TIMER_ABSTIME) == 0 && 369b215ceaaSEric van Gyzen rqtp != NULL && rmtp != NULL) { 370b215ceaaSEric van Gyzen *rmtp = tms.remain; 371b215ceaaSEric van Gyzen } 372b215ceaaSEric van Gyzen 373b215ceaaSEric van Gyzen return (retval); 3749b0f1823SDavid Xu } 3759b0f1823SDavid Xu 3769b0f1823SDavid Xu int 377523a738fSDavid Xu _sem_trywait(sem_t *sem) 3789b0f1823SDavid Xu { 3794e2158bfSDavid Xu int val; 3809b0f1823SDavid Xu 3819b0f1823SDavid Xu if (sem_check_validity(sem) != 0) 3829b0f1823SDavid Xu return (-1); 3834e2158bfSDavid Xu 38453e1ffbbSJohn Baldwin while (USEM_COUNT(val = sem->_kern._count) > 0) { 3854e2158bfSDavid Xu if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1)) 3869b0f1823SDavid Xu return (0); 3874e2158bfSDavid Xu } 3884e2158bfSDavid Xu errno = EAGAIN; 3899b0f1823SDavid Xu return (-1); 3909b0f1823SDavid Xu } 3919b0f1823SDavid Xu 3929b0f1823SDavid Xu int 393b215ceaaSEric van Gyzen _sem_clockwait_np(sem_t * __restrict sem, clockid_t clock_id, int flags, 394b215ceaaSEric van Gyzen const struct timespec *rqtp, struct timespec *rmtp) 3959b0f1823SDavid Xu { 3964e2158bfSDavid Xu int val, retval; 3979b0f1823SDavid Xu 3989b0f1823SDavid Xu if (sem_check_validity(sem) != 0) 3999b0f1823SDavid Xu return (-1); 4009b0f1823SDavid Xu 4019b0f1823SDavid Xu retval = 0; 402ddf06178SDavid Xu _pthread_testcancel(); 4039b0f1823SDavid Xu for (;;) { 40453e1ffbbSJohn Baldwin while (USEM_COUNT(val = sem->_kern._count) > 0) { 405b215ceaaSEric van Gyzen if (atomic_cmpset_acq_int(&sem->_kern._count, val, 406b215ceaaSEric van Gyzen val - 1)) 4079b0f1823SDavid Xu return (0); 4084e2158bfSDavid Xu } 4099b0f1823SDavid Xu 410f4213b90SDavid Xu if (retval) { 411f4213b90SDavid Xu _pthread_testcancel(); 4129b0f1823SDavid Xu break; 413f4213b90SDavid Xu } 4149b0f1823SDavid Xu 4159b0f1823SDavid Xu /* 4169b0f1823SDavid Xu * The timeout argument is only supposed to 4179b0f1823SDavid Xu * be checked if the thread would have blocked. 4189b0f1823SDavid Xu */ 419b215ceaaSEric van Gyzen if (rqtp != NULL) { 420b215ceaaSEric van Gyzen if (rqtp->tv_nsec >= 1000000000 || rqtp->tv_nsec < 0) { 4219b0f1823SDavid Xu errno = EINVAL; 4229b0f1823SDavid Xu return (-1); 4239b0f1823SDavid Xu } 4249b0f1823SDavid Xu } 425f4213b90SDavid Xu _pthread_cancel_enter(1); 426b215ceaaSEric van Gyzen retval = usem_wait(&sem->_kern, clock_id, flags, rqtp, rmtp); 427f4213b90SDavid Xu _pthread_cancel_leave(0); 4289b0f1823SDavid Xu } 4299b0f1823SDavid Xu return (retval); 4309b0f1823SDavid Xu } 4319b0f1823SDavid Xu 4329b0f1823SDavid Xu int 433b215ceaaSEric van Gyzen _sem_timedwait(sem_t * __restrict sem, 434b215ceaaSEric van Gyzen const struct timespec * __restrict abstime) 435b215ceaaSEric van Gyzen { 4363a137162SKonstantin Belousov 437b215ceaaSEric van Gyzen return (_sem_clockwait_np(sem, CLOCK_REALTIME, TIMER_ABSTIME, abstime, 438b215ceaaSEric van Gyzen NULL)); 439b215ceaaSEric van Gyzen }; 440b215ceaaSEric van Gyzen 441b215ceaaSEric van Gyzen int 442523a738fSDavid Xu _sem_wait(sem_t *sem) 4439b0f1823SDavid Xu { 4443a137162SKonstantin Belousov 4453a137162SKonstantin Belousov return (_sem_timedwait(sem, NULL)); 4469b0f1823SDavid Xu } 4479b0f1823SDavid Xu 4489b0f1823SDavid Xu /* 4499b0f1823SDavid Xu * POSIX: 4509b0f1823SDavid Xu * The sem_post() interface is reentrant with respect to signals and may be 4519b0f1823SDavid Xu * invoked from a signal-catching function. 4529b0f1823SDavid Xu * The implementation does not use lock, so it should be safe. 4539b0f1823SDavid Xu */ 4549b0f1823SDavid Xu int 455523a738fSDavid Xu _sem_post(sem_t *sem) 4569b0f1823SDavid Xu { 4578931e524SDavid Xu unsigned int count; 4589b0f1823SDavid Xu 4599b0f1823SDavid Xu if (sem_check_validity(sem) != 0) 4609b0f1823SDavid Xu return (-1); 4619b0f1823SDavid Xu 4628931e524SDavid Xu do { 4638931e524SDavid Xu count = sem->_kern._count; 46449ba8a68SJilles Tjoelker if (USEM_COUNT(count) + 1 > SEM_VALUE_MAX) { 46549ba8a68SJilles Tjoelker errno = EOVERFLOW; 46649ba8a68SJilles Tjoelker return (-1); 46749ba8a68SJilles Tjoelker } 4688931e524SDavid Xu } while (!atomic_cmpset_rel_int(&sem->_kern._count, count, count + 1)); 46953e1ffbbSJohn Baldwin if (count & USEM_HAS_WAITERS) 47053e1ffbbSJohn Baldwin usem_wake(&sem->_kern); 4718931e524SDavid Xu return (0); 4729b0f1823SDavid Xu } 473