1d915a14eSPedro F. Giffuni /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3d915a14eSPedro F. Giffuni *
49b0f1823SDavid Xu * Copyright (C) 2010 David Xu <davidxu@freebsd.org>.
5bf4dc877SAlfred Perlstein * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
6bf4dc877SAlfred Perlstein * All rights reserved.
7bf4dc877SAlfred Perlstein *
8bf4dc877SAlfred Perlstein * Redistribution and use in source and binary forms, with or without
9bf4dc877SAlfred Perlstein * modification, are permitted provided that the following conditions
10bf4dc877SAlfred Perlstein * are met:
11bf4dc877SAlfred Perlstein * 1. Redistributions of source code must retain the above copyright
12bf4dc877SAlfred Perlstein * notice(s), this list of conditions and the following disclaimer as
13bf4dc877SAlfred Perlstein * the first lines of this file unmodified other than the possible
14bf4dc877SAlfred Perlstein * addition of one or more copyright notices.
15bf4dc877SAlfred Perlstein * 2. Redistributions in binary form must reproduce the above copyright
16bf4dc877SAlfred Perlstein * notice(s), this list of conditions and the following disclaimer in
17bf4dc877SAlfred Perlstein * the documentation and/or other materials provided with the
18bf4dc877SAlfred Perlstein * distribution.
19bf4dc877SAlfred Perlstein *
20bf4dc877SAlfred Perlstein * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
21bf4dc877SAlfred Perlstein * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22bf4dc877SAlfred Perlstein * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23bf4dc877SAlfred Perlstein * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
24bf4dc877SAlfred Perlstein * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25bf4dc877SAlfred Perlstein * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26bf4dc877SAlfred Perlstein * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27bf4dc877SAlfred Perlstein * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28bf4dc877SAlfred Perlstein * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29bf4dc877SAlfred Perlstein * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30bf4dc877SAlfred Perlstein * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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
sem_check_validity(sem_t * sem)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
sem_free(sem_t sem)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
sem_alloc(unsigned int value,semid_t semid,int system_sem)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
_libc_sem_init_compat(sem_t * sem,int pshared,unsigned int value)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
_libc_sem_destroy_compat(sem_t * sem)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 *
_libc_sem_open_compat(const char * name,int oflag,...)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
_libc_sem_close_compat(sem_t * sem)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
_libc_sem_unlink_compat(const char * name)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
_umtx_wait_uint(volatile unsigned * mtx,unsigned id,const struct timespec * abstime)315df1f1baeSDavid Xu _umtx_wait_uint(volatile unsigned *mtx, unsigned id, const struct timespec *abstime)
3169b0f1823SDavid Xu {
317df1f1baeSDavid Xu struct _umtx_time *tm_p, timeout;
318df1f1baeSDavid Xu size_t tm_size;
319df1f1baeSDavid Xu
320df1f1baeSDavid Xu if (abstime == NULL) {
321df1f1baeSDavid Xu tm_p = NULL;
322df1f1baeSDavid Xu tm_size = 0;
323df1f1baeSDavid Xu } else {
324df1f1baeSDavid Xu timeout._clockid = CLOCK_REALTIME;
325df1f1baeSDavid Xu timeout._flags = UMTX_ABSTIME;
326df1f1baeSDavid Xu timeout._timeout = *abstime;
327df1f1baeSDavid Xu tm_p = &timeout;
328df1f1baeSDavid Xu tm_size = sizeof(timeout);
3299b0f1823SDavid Xu }
3309b0f1823SDavid Xu return _umtx_op(__DEVOLATILE(void *, mtx),
331df1f1baeSDavid Xu UMTX_OP_WAIT_UINT_PRIVATE, id,
332df1f1baeSDavid Xu (void *)tm_size, __DECONST(void*, tm_p));
3339b0f1823SDavid Xu }
334bf4dc877SAlfred Perlstein
3359b0f1823SDavid Xu static int
_umtx_wake(volatile void * mtx)3369b0f1823SDavid Xu _umtx_wake(volatile void *mtx)
3379b0f1823SDavid Xu {
3389b0f1823SDavid Xu return _umtx_op(__DEVOLATILE(void *, mtx), UMTX_OP_WAKE_PRIVATE,
3399b0f1823SDavid Xu 1, NULL, NULL);
3409b0f1823SDavid Xu }
3419b0f1823SDavid Xu
3429b0f1823SDavid Xu #define TIMESPEC_SUB(dst, src, val) \
3439b0f1823SDavid Xu do { \
3449b0f1823SDavid Xu (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \
3459b0f1823SDavid Xu (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \
3469b0f1823SDavid Xu if ((dst)->tv_nsec < 0) { \
3479b0f1823SDavid Xu (dst)->tv_sec--; \
3489b0f1823SDavid Xu (dst)->tv_nsec += 1000000000; \
3499b0f1823SDavid Xu } \
3509b0f1823SDavid Xu } while (0)
3519b0f1823SDavid Xu
3529b0f1823SDavid Xu
3539b0f1823SDavid Xu static void
sem_cancel_handler(void * arg)3549b0f1823SDavid Xu sem_cancel_handler(void *arg)
3559b0f1823SDavid Xu {
3569b0f1823SDavid Xu sem_t *sem = arg;
3579b0f1823SDavid Xu
3589b0f1823SDavid Xu atomic_add_int(&(*sem)->nwaiters, -1);
3599b0f1823SDavid Xu if ((*sem)->nwaiters && (*sem)->count)
3609b0f1823SDavid Xu _umtx_wake(&(*sem)->count);
361bf4dc877SAlfred Perlstein }
362bf4dc877SAlfred Perlstein
363bf4dc877SAlfred Perlstein int
_libc_sem_timedwait_compat(sem_t * __restrict sem,const struct timespec * __restrict abstime)3649b0f1823SDavid Xu _libc_sem_timedwait_compat(sem_t * __restrict sem,
3659b0f1823SDavid Xu const struct timespec * __restrict abstime)
366bf4dc877SAlfred Perlstein {
367f4213b90SDavid Xu int val, retval;
368bf4dc877SAlfred Perlstein
3695c70dac8SDaniel Eischen if (sem_check_validity(sem) != 0)
3705c70dac8SDaniel Eischen return (-1);
371bf4dc877SAlfred Perlstein
3729b0f1823SDavid Xu if ((*sem)->syssem != 0) {
373f4213b90SDavid Xu _pthread_cancel_enter(1);
374f4213b90SDavid Xu retval = ksem_wait((*sem)->semid); /* XXX no timeout */
375f4213b90SDavid Xu _pthread_cancel_leave(retval == -1);
3769b0f1823SDavid Xu return (retval);
3779b0f1823SDavid Xu }
3789b0f1823SDavid Xu
379903f2e50SDaniel Eischen retval = 0;
3809b0f1823SDavid Xu _pthread_testcancel();
3819b0f1823SDavid Xu for (;;) {
3829b0f1823SDavid Xu while ((val = (*sem)->count) > 0) {
3839b0f1823SDavid Xu if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
3849b0f1823SDavid Xu return (0);
385903f2e50SDaniel Eischen }
386f4213b90SDavid Xu if (retval) {
387f4213b90SDavid Xu _pthread_testcancel();
3889b0f1823SDavid Xu break;
389f4213b90SDavid Xu }
3909b0f1823SDavid Xu if (abstime) {
3919b0f1823SDavid Xu if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) {
3929b0f1823SDavid Xu errno = EINVAL;
3939b0f1823SDavid Xu return (-1);
3949b0f1823SDavid Xu }
3959b0f1823SDavid Xu }
3969b0f1823SDavid Xu atomic_add_int(&(*sem)->nwaiters, 1);
3979b0f1823SDavid Xu pthread_cleanup_push(sem_cancel_handler, sem);
398f4213b90SDavid Xu _pthread_cancel_enter(1);
399df1f1baeSDavid Xu retval = _umtx_wait_uint(&(*sem)->count, 0, abstime);
400f4213b90SDavid Xu _pthread_cancel_leave(0);
4019b0f1823SDavid Xu pthread_cleanup_pop(0);
4029b0f1823SDavid Xu atomic_add_int(&(*sem)->nwaiters, -1);
403903f2e50SDaniel Eischen }
404903f2e50SDaniel Eischen return (retval);
405bf4dc877SAlfred Perlstein }
406bf4dc877SAlfred Perlstein
407bf4dc877SAlfred Perlstein int
_libc_sem_wait_compat(sem_t * sem)4089b0f1823SDavid Xu _libc_sem_wait_compat(sem_t *sem)
409bf4dc877SAlfred Perlstein {
4109b0f1823SDavid Xu return _libc_sem_timedwait_compat(sem, NULL);
411bf4dc877SAlfred Perlstein }
412bf4dc877SAlfred Perlstein
413bf4dc877SAlfred Perlstein int
_libc_sem_trywait_compat(sem_t * sem)4149b0f1823SDavid Xu _libc_sem_trywait_compat(sem_t *sem)
4159b0f1823SDavid Xu {
4169b0f1823SDavid Xu int val;
4179b0f1823SDavid Xu
4189b0f1823SDavid Xu if (sem_check_validity(sem) != 0)
4199b0f1823SDavid Xu return (-1);
4209b0f1823SDavid Xu
4219b0f1823SDavid Xu if ((*sem)->syssem != 0)
4229b0f1823SDavid Xu return ksem_trywait((*sem)->semid);
4239b0f1823SDavid Xu
4249b0f1823SDavid Xu while ((val = (*sem)->count) > 0) {
4259b0f1823SDavid Xu if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
4269b0f1823SDavid Xu return (0);
4279b0f1823SDavid Xu }
4289b0f1823SDavid Xu errno = EAGAIN;
4299b0f1823SDavid Xu return (-1);
4309b0f1823SDavid Xu }
4319b0f1823SDavid Xu
4329b0f1823SDavid Xu int
_libc_sem_post_compat(sem_t * sem)4339b0f1823SDavid Xu _libc_sem_post_compat(sem_t *sem)
4345c70dac8SDaniel Eischen {
4355c70dac8SDaniel Eischen
4365c70dac8SDaniel Eischen if (sem_check_validity(sem) != 0)
4375c70dac8SDaniel Eischen return (-1);
4385c70dac8SDaniel Eischen
4399b0f1823SDavid Xu if ((*sem)->syssem != 0)
4409b0f1823SDavid Xu return ksem_post((*sem)->semid);
4419b0f1823SDavid Xu
4429b0f1823SDavid Xu atomic_add_rel_int(&(*sem)->count, 1);
443d22d46ceSDavid Xu rmb();
4449b0f1823SDavid Xu if ((*sem)->nwaiters)
4459b0f1823SDavid Xu return _umtx_wake(&(*sem)->count);
4469b0f1823SDavid Xu return (0);
4475c70dac8SDaniel Eischen }
4485c70dac8SDaniel Eischen
4495c70dac8SDaniel Eischen int
_libc_sem_getvalue_compat(sem_t * __restrict sem,int * __restrict sval)4509b0f1823SDavid Xu _libc_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval)
451bf4dc877SAlfred Perlstein {
452bf4dc877SAlfred Perlstein int retval;
453bf4dc877SAlfred Perlstein
4545c70dac8SDaniel Eischen if (sem_check_validity(sem) != 0)
4555c70dac8SDaniel Eischen return (-1);
456bf4dc877SAlfred Perlstein
4575c70dac8SDaniel Eischen if ((*sem)->syssem != 0)
458bf4dc877SAlfred Perlstein retval = ksem_getvalue((*sem)->semid, sval);
4595c70dac8SDaniel Eischen else {
460bf4dc877SAlfred Perlstein *sval = (int)(*sem)->count;
461bf4dc877SAlfred Perlstein retval = 0;
4625c70dac8SDaniel Eischen }
4635c70dac8SDaniel Eischen return (retval);
464bf4dc877SAlfred Perlstein }
465