171b3fa15SDavid Xu /*
271b3fa15SDavid Xu * Copyright (C) 2005 David Xu <davidxu@freebsd.org>.
371b3fa15SDavid Xu * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
471b3fa15SDavid Xu * All rights reserved.
571b3fa15SDavid Xu *
671b3fa15SDavid Xu * Redistribution and use in source and binary forms, with or without
771b3fa15SDavid Xu * modification, are permitted provided that the following conditions
871b3fa15SDavid Xu * are met:
971b3fa15SDavid Xu * 1. Redistributions of source code must retain the above copyright
1071b3fa15SDavid Xu * notice(s), this list of conditions and the following disclaimer as
1171b3fa15SDavid Xu * the first lines of this file unmodified other than the possible
1271b3fa15SDavid Xu * addition of one or more copyright notices.
1371b3fa15SDavid Xu * 2. Redistributions in binary form must reproduce the above copyright
1471b3fa15SDavid Xu * notice(s), this list of conditions and the following disclaimer in
1571b3fa15SDavid Xu * the documentation and/or other materials provided with the
1671b3fa15SDavid Xu * distribution.
1771b3fa15SDavid Xu *
1871b3fa15SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
1971b3fa15SDavid Xu * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2071b3fa15SDavid Xu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2171b3fa15SDavid Xu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
2271b3fa15SDavid Xu * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2371b3fa15SDavid Xu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2471b3fa15SDavid Xu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
2571b3fa15SDavid Xu * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2671b3fa15SDavid Xu * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
2771b3fa15SDavid Xu * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
2871b3fa15SDavid Xu * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2971b3fa15SDavid Xu */
3071b3fa15SDavid Xu
31fc71f871SDavid Xu #include "namespace.h"
329e2ee207SJoerg Sonnenberger #include <machine/tls.h>
33328161bdSMatthew Dillon #include <sys/mman.h>
341a09a5c7SJoris Giovannangeli #include <sys/queue.h>
351a09a5c7SJoris Giovannangeli #include <sys/stat.h>
361a09a5c7SJoris Giovannangeli #include <sys/types.h>
3771b3fa15SDavid Xu #include <errno.h>
3871b3fa15SDavid Xu #include <fcntl.h>
391a09a5c7SJoris Giovannangeli #include <limits.h>
4071b3fa15SDavid Xu #include <pthread.h>
4194f03308SSascha Wildner #include <semaphore.h>
421a09a5c7SJoris Giovannangeli #include <stdarg.h>
4371b3fa15SDavid Xu #include <stdlib.h>
441a09a5c7SJoris Giovannangeli #include <string.h>
4571b3fa15SDavid Xu #include <time.h>
461a09a5c7SJoris Giovannangeli #include <unistd.h>
4798247283SMatthew Dillon #ifdef _PTHREADS_DEBUGGING
4898247283SMatthew Dillon #include <stdio.h>
4998247283SMatthew Dillon #endif
50fc71f871SDavid Xu #include "un-namespace.h"
5119451dc5Szrj
5271b3fa15SDavid Xu #include "thr_private.h"
5371b3fa15SDavid Xu
5498247283SMatthew Dillon #define cpu_ccfence() __asm __volatile("" : : : "memory")
5598247283SMatthew Dillon
561a09a5c7SJoris Giovannangeli #define container_of(ptr, type, member) \
571a09a5c7SJoris Giovannangeli ({ \
581a09a5c7SJoris Giovannangeli __typeof(((type *)0)->member) *_p = (ptr); \
591a09a5c7SJoris Giovannangeli (type *)((char *)_p - offsetof(type, member)); \
601a09a5c7SJoris Giovannangeli })
611a09a5c7SJoris Giovannangeli
6271b3fa15SDavid Xu /*
6371b3fa15SDavid Xu * Semaphore definitions.
6471b3fa15SDavid Xu */
6571b3fa15SDavid Xu struct sem {
6671b3fa15SDavid Xu volatile umtx_t count;
6798247283SMatthew Dillon u_int32_t magic;
68328161bdSMatthew Dillon int semid;
69328161bdSMatthew Dillon int unused; /* pad */
7098247283SMatthew Dillon } __cachealign;
7171b3fa15SDavid Xu
72328161bdSMatthew Dillon #define SEM_MAGIC ((u_int32_t) 0x09fa4012)
73328161bdSMatthew Dillon
741a09a5c7SJoris Giovannangeli static char const *sem_prefix = "/var/run/sem";
751a09a5c7SJoris Giovannangeli
761a09a5c7SJoris Giovannangeli
771a09a5c7SJoris Giovannangeli /*
781a09a5c7SJoris Giovannangeli * POSIX requires that two successive calls to sem_open return
791a09a5c7SJoris Giovannangeli * the same address if no call to unlink nor close have been
801a09a5c7SJoris Giovannangeli * done in the middle. For that, we keep a list of open semaphore
811a09a5c7SJoris Giovannangeli * and search for an existing one before remapping a semaphore.
821a09a5c7SJoris Giovannangeli * We have to keep the fd open to check for races.
831a09a5c7SJoris Giovannangeli *
841a09a5c7SJoris Giovannangeli * Example :
851a09a5c7SJoris Giovannangeli * sem_open("/test", O_CREAT | O_EXCL...) -> fork() ->
861a09a5c7SJoris Giovannangeli * parent :
871a09a5c7SJoris Giovannangeli * sem_unlink("/test") -> sem_open("/test", O_CREAT | O_EXCl ...)
881a09a5c7SJoris Giovannangeli * child :
891a09a5c7SJoris Giovannangeli * sem_open("/test", 0).
901a09a5c7SJoris Giovannangeli * We need to check that the cached mapping is the one of the most up
911a09a5c7SJoris Giovannangeli * to date file linked at this name, or child process will reopen the
921a09a5c7SJoris Giovannangeli * *old* version of the semaphore, which is wrong.
931a09a5c7SJoris Giovannangeli *
941a09a5c7SJoris Giovannangeli * fstat and nlink check is used to test for this race.
951a09a5c7SJoris Giovannangeli */
961a09a5c7SJoris Giovannangeli
971a09a5c7SJoris Giovannangeli struct sem_info {
981a09a5c7SJoris Giovannangeli int open_count;
991a09a5c7SJoris Giovannangeli ino_t inode;
1001a09a5c7SJoris Giovannangeli dev_t dev;
1011a09a5c7SJoris Giovannangeli int fd;
1021a09a5c7SJoris Giovannangeli sem_t sem;
1031a09a5c7SJoris Giovannangeli LIST_ENTRY(sem_info) next;
1041a09a5c7SJoris Giovannangeli };
1051a09a5c7SJoris Giovannangeli
1061a09a5c7SJoris Giovannangeli static pthread_mutex_t sem_lock;
1071a09a5c7SJoris Giovannangeli static LIST_HEAD(,sem_info) sem_list = LIST_HEAD_INITIALIZER(sem_list);
1081a09a5c7SJoris Giovannangeli
10998247283SMatthew Dillon #ifdef _PTHREADS_DEBUGGING
11098247283SMatthew Dillon
11198247283SMatthew Dillon static
11298247283SMatthew Dillon void
sem_log(const char * ctl,...)11398247283SMatthew Dillon sem_log(const char *ctl, ...)
11498247283SMatthew Dillon {
11598247283SMatthew Dillon char buf[256];
11698247283SMatthew Dillon va_list va;
11798247283SMatthew Dillon size_t len;
11898247283SMatthew Dillon
11998247283SMatthew Dillon va_start(va, ctl);
12098247283SMatthew Dillon len = vsnprintf(buf, sizeof(buf), ctl, va);
12198247283SMatthew Dillon va_end(va);
12298247283SMatthew Dillon _thr_log(buf, len);
12398247283SMatthew Dillon }
12498247283SMatthew Dillon
12598247283SMatthew Dillon #else
12698247283SMatthew Dillon
12798247283SMatthew Dillon static __inline
12898247283SMatthew Dillon void
sem_log(const char * ctl __unused,...)12998247283SMatthew Dillon sem_log(const char *ctl __unused, ...)
13098247283SMatthew Dillon {
13198247283SMatthew Dillon }
13298247283SMatthew Dillon
13398247283SMatthew Dillon #endif
1341a09a5c7SJoris Giovannangeli
135328161bdSMatthew Dillon #define SEMID_LWP 0
136328161bdSMatthew Dillon #define SEMID_FORK 1
1371a09a5c7SJoris Giovannangeli #define SEMID_NAMED 2
1381a09a5c7SJoris Giovannangeli
1391a09a5c7SJoris Giovannangeli static void
sem_prefork(void)1401a09a5c7SJoris Giovannangeli sem_prefork(void)
1411a09a5c7SJoris Giovannangeli {
1421a09a5c7SJoris Giovannangeli _pthread_mutex_lock(&sem_lock);
1431a09a5c7SJoris Giovannangeli }
1441a09a5c7SJoris Giovannangeli
1451a09a5c7SJoris Giovannangeli static void
sem_postfork(void)1461a09a5c7SJoris Giovannangeli sem_postfork(void)
1471a09a5c7SJoris Giovannangeli {
1481a09a5c7SJoris Giovannangeli _pthread_mutex_unlock(&sem_lock);
1491a09a5c7SJoris Giovannangeli }
1501a09a5c7SJoris Giovannangeli
1511a09a5c7SJoris Giovannangeli static void
sem_child_postfork(void)1521a09a5c7SJoris Giovannangeli sem_child_postfork(void)
1531a09a5c7SJoris Giovannangeli {
1541a09a5c7SJoris Giovannangeli _pthread_mutex_unlock(&sem_lock);
1551a09a5c7SJoris Giovannangeli }
1561a09a5c7SJoris Giovannangeli
15798247283SMatthew Dillon void
_thr_sem_init(void)15898247283SMatthew Dillon _thr_sem_init(void)
1591a09a5c7SJoris Giovannangeli {
1601a09a5c7SJoris Giovannangeli pthread_mutexattr_t ma;
1611a09a5c7SJoris Giovannangeli
1621a09a5c7SJoris Giovannangeli _pthread_mutexattr_init(&ma);
1631a09a5c7SJoris Giovannangeli _pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
1641a09a5c7SJoris Giovannangeli _pthread_mutex_init(&sem_lock, &ma);
1651a09a5c7SJoris Giovannangeli _pthread_mutexattr_destroy(&ma);
166fcaa7a3aSMatthew Dillon _thr_atfork_kern(sem_prefork, sem_postfork, sem_child_postfork);
1671a09a5c7SJoris Giovannangeli }
168328161bdSMatthew Dillon
16971b3fa15SDavid Xu static inline int
sem_check_validity(sem_t * sem)17071b3fa15SDavid Xu sem_check_validity(sem_t *sem)
17171b3fa15SDavid Xu {
17271b3fa15SDavid Xu
173f36c8b06SSascha Wildner if ((sem != NULL) && (*sem != NULL) && ((*sem)->magic == SEM_MAGIC)) {
17471b3fa15SDavid Xu return (0);
175328161bdSMatthew Dillon } else {
17671b3fa15SDavid Xu errno = EINVAL;
17771b3fa15SDavid Xu return (-1);
17871b3fa15SDavid Xu }
17971b3fa15SDavid Xu }
18071b3fa15SDavid Xu
18171b3fa15SDavid Xu static sem_t
sem_alloc(unsigned int value,int pshared)182328161bdSMatthew Dillon sem_alloc(unsigned int value, int pshared)
18371b3fa15SDavid Xu {
18471b3fa15SDavid Xu sem_t sem;
185328161bdSMatthew Dillon int semid;
18671b3fa15SDavid Xu
18771b3fa15SDavid Xu if (value > SEM_VALUE_MAX) {
18871b3fa15SDavid Xu errno = EINVAL;
18971b3fa15SDavid Xu return (NULL);
19071b3fa15SDavid Xu }
191328161bdSMatthew Dillon if (pshared) {
192328161bdSMatthew Dillon static __thread sem_t sem_base;
193328161bdSMatthew Dillon static __thread int sem_count;
19471b3fa15SDavid Xu
195328161bdSMatthew Dillon if (sem_base == NULL) {
196328161bdSMatthew Dillon sem_base = mmap(NULL, getpagesize(),
197328161bdSMatthew Dillon PROT_READ | PROT_WRITE,
198328161bdSMatthew Dillon MAP_ANON | MAP_SHARED,
199328161bdSMatthew Dillon -1, 0);
200328161bdSMatthew Dillon sem_count = getpagesize() / sizeof(*sem);
201328161bdSMatthew Dillon }
202328161bdSMatthew Dillon sem = sem_base++;
203328161bdSMatthew Dillon if (--sem_count == 0)
204328161bdSMatthew Dillon sem_base = NULL;
205328161bdSMatthew Dillon semid = SEMID_FORK;
206328161bdSMatthew Dillon } else {
207e7bf3f77SMatthew Dillon sem = __malloc(sizeof(struct sem));
208328161bdSMatthew Dillon semid = SEMID_LWP;
209328161bdSMatthew Dillon }
21071b3fa15SDavid Xu if (sem == NULL) {
21171b3fa15SDavid Xu errno = ENOSPC;
21271b3fa15SDavid Xu return (NULL);
21371b3fa15SDavid Xu }
21471b3fa15SDavid Xu sem->magic = SEM_MAGIC;
21571b3fa15SDavid Xu sem->count = (u_int32_t)value;
21671b3fa15SDavid Xu sem->semid = semid;
21798247283SMatthew Dillon
21898247283SMatthew Dillon sem_log("sem_alloc %p (%d)\n", sem, value);
21998247283SMatthew Dillon
22071b3fa15SDavid Xu return (sem);
22171b3fa15SDavid Xu }
22271b3fa15SDavid Xu
22371b3fa15SDavid Xu int
_sem_init(sem_t * sem,int pshared,unsigned int value)22471b3fa15SDavid Xu _sem_init(sem_t *sem, int pshared, unsigned int value)
22571b3fa15SDavid Xu {
2261a09a5c7SJoris Giovannangeli if (sem == NULL) {
2271a09a5c7SJoris Giovannangeli errno = EINVAL;
2281a09a5c7SJoris Giovannangeli return (-1);
2291a09a5c7SJoris Giovannangeli }
2301a09a5c7SJoris Giovannangeli
2311a09a5c7SJoris Giovannangeli *sem = sem_alloc(value, pshared);
2321a09a5c7SJoris Giovannangeli if (*sem == NULL)
23371b3fa15SDavid Xu return (-1);
23471b3fa15SDavid Xu return (0);
23571b3fa15SDavid Xu }
23671b3fa15SDavid Xu
23771b3fa15SDavid Xu int
_sem_destroy(sem_t * sem)23871b3fa15SDavid Xu _sem_destroy(sem_t *sem)
23971b3fa15SDavid Xu {
2401a09a5c7SJoris Giovannangeli if (sem_check_validity(sem) != 0) {
2411a09a5c7SJoris Giovannangeli errno = EINVAL;
24271b3fa15SDavid Xu return (-1);
2431a09a5c7SJoris Giovannangeli }
24471b3fa15SDavid Xu
245328161bdSMatthew Dillon (*sem)->magic = 0;
246328161bdSMatthew Dillon
247328161bdSMatthew Dillon switch ((*sem)->semid) {
248328161bdSMatthew Dillon case SEMID_LWP:
249e7bf3f77SMatthew Dillon __free(*sem);
250328161bdSMatthew Dillon break;
251328161bdSMatthew Dillon case SEMID_FORK:
252328161bdSMatthew Dillon /* memory is left intact */
253328161bdSMatthew Dillon break;
2541a09a5c7SJoris Giovannangeli default:
2551a09a5c7SJoris Giovannangeli errno = EINVAL;
2561a09a5c7SJoris Giovannangeli return (-1);
257328161bdSMatthew Dillon }
25871b3fa15SDavid Xu return (0);
25971b3fa15SDavid Xu }
26071b3fa15SDavid Xu
26171b3fa15SDavid Xu int
_sem_getvalue(sem_t * __restrict sem,int * __restrict sval)26271b3fa15SDavid Xu _sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
26371b3fa15SDavid Xu {
264fcaa7a3aSMatthew Dillon if (sem_check_validity(sem) != 0) {
265fcaa7a3aSMatthew Dillon errno = EINVAL;
26671b3fa15SDavid Xu return (-1);
267fcaa7a3aSMatthew Dillon }
26871b3fa15SDavid Xu *sval = (*sem)->count;
26998247283SMatthew Dillon
27071b3fa15SDavid Xu return (0);
27171b3fa15SDavid Xu }
27271b3fa15SDavid Xu
27371b3fa15SDavid Xu int
_sem_trywait(sem_t * sem)27471b3fa15SDavid Xu _sem_trywait(sem_t *sem)
27571b3fa15SDavid Xu {
27671b3fa15SDavid Xu int val;
27771b3fa15SDavid Xu
278fcaa7a3aSMatthew Dillon if (sem_check_validity(sem) != 0) {
279fcaa7a3aSMatthew Dillon errno = EINVAL;
28071b3fa15SDavid Xu return (-1);
281fcaa7a3aSMatthew Dillon }
28271b3fa15SDavid Xu
28398247283SMatthew Dillon sem_log("sem_trywait %p %d\n", *sem, (*sem)->count);
28471b3fa15SDavid Xu while ((val = (*sem)->count) > 0) {
28598247283SMatthew Dillon cpu_ccfence();
28698247283SMatthew Dillon if (atomic_cmpset_int(&(*sem)->count, val, val - 1)) {
28798247283SMatthew Dillon sem_log("sem_trywait %p %d (success)\n", *sem, val - 1);
28871b3fa15SDavid Xu return (0);
28971b3fa15SDavid Xu }
29098247283SMatthew Dillon }
29171b3fa15SDavid Xu errno = EAGAIN;
29298247283SMatthew Dillon sem_log("sem_trywait %p %d (failure)\n", *sem, val);
29371b3fa15SDavid Xu return (-1);
29471b3fa15SDavid Xu }
29571b3fa15SDavid Xu
29671b3fa15SDavid Xu int
_sem_wait(sem_t * sem)29771b3fa15SDavid Xu _sem_wait(sem_t *sem)
29871b3fa15SDavid Xu {
299*940be950Szrj pthread_t curthread;
30071b3fa15SDavid Xu int val, oldcancel, retval;
30171b3fa15SDavid Xu
302fcaa7a3aSMatthew Dillon if (sem_check_validity(sem) != 0) {
303fcaa7a3aSMatthew Dillon errno = EINVAL;
30471b3fa15SDavid Xu return (-1);
305fcaa7a3aSMatthew Dillon }
30671b3fa15SDavid Xu
3079e2ee207SJoerg Sonnenberger curthread = tls_get_curthread();
30871b3fa15SDavid Xu _pthread_testcancel();
309fcaa7a3aSMatthew Dillon
31098247283SMatthew Dillon sem_log("sem_wait %p %d (begin)\n", *sem, (*sem)->count);
31198247283SMatthew Dillon
31298247283SMatthew Dillon do {
31398247283SMatthew Dillon cpu_ccfence();
31471b3fa15SDavid Xu while ((val = (*sem)->count) > 0) {
31598247283SMatthew Dillon cpu_ccfence();
31698247283SMatthew Dillon if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) {
31798247283SMatthew Dillon sem_log("sem_wait %p %d (success)\n",
31898247283SMatthew Dillon *sem, val - 1);
31971b3fa15SDavid Xu return (0);
32071b3fa15SDavid Xu }
32198247283SMatthew Dillon }
32271b3fa15SDavid Xu oldcancel = _thr_cancel_enter(curthread);
32398247283SMatthew Dillon sem_log("sem_wait %p %d (wait)\n", *sem, val);
32498247283SMatthew Dillon retval = _thr_umtx_wait_intr(&(*sem)->count, 0);
32598247283SMatthew Dillon sem_log("sem_wait %p %d (wait return %d)\n",
32698247283SMatthew Dillon *sem, (*sem)->count, retval);
32771b3fa15SDavid Xu _thr_cancel_leave(curthread, oldcancel);
328fcaa7a3aSMatthew Dillon /* ignore retval */
32998247283SMatthew Dillon } while (retval != EINTR);
330fcaa7a3aSMatthew Dillon
33198247283SMatthew Dillon sem_log("sem_wait %p %d (error %d)\n", *sem, retval);
33271b3fa15SDavid Xu errno = retval;
333fcaa7a3aSMatthew Dillon
33471b3fa15SDavid Xu return (-1);
33571b3fa15SDavid Xu }
33671b3fa15SDavid Xu
33771b3fa15SDavid Xu int
_sem_timedwait(sem_t * __restrict sem,const struct timespec * __restrict abstime)338a5c6fa83SSascha Wildner _sem_timedwait(sem_t * __restrict sem, const struct timespec * __restrict abstime)
33971b3fa15SDavid Xu {
34071b3fa15SDavid Xu struct timespec ts, ts2;
341*940be950Szrj pthread_t curthread;
34271b3fa15SDavid Xu int val, oldcancel, retval;
34371b3fa15SDavid Xu
34471b3fa15SDavid Xu if (sem_check_validity(sem) != 0)
34571b3fa15SDavid Xu return (-1);
34671b3fa15SDavid Xu
3479e2ee207SJoerg Sonnenberger curthread = tls_get_curthread();
348fcaa7a3aSMatthew Dillon _pthread_testcancel();
34998247283SMatthew Dillon sem_log("sem_timedwait %p %d (begin)\n", *sem, (*sem)->count);
35071b3fa15SDavid Xu
35171b3fa15SDavid Xu /*
35271b3fa15SDavid Xu * The timeout argument is only supposed to
35371b3fa15SDavid Xu * be checked if the thread would have blocked.
35471b3fa15SDavid Xu */
35571b3fa15SDavid Xu do {
35671b3fa15SDavid Xu while ((val = (*sem)->count) > 0) {
35798247283SMatthew Dillon cpu_ccfence();
35898247283SMatthew Dillon if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) {
35998247283SMatthew Dillon sem_log("sem_wait %p %d (success)\n",
36098247283SMatthew Dillon *sem, val - 1);
36171b3fa15SDavid Xu return (0);
36271b3fa15SDavid Xu }
36398247283SMatthew Dillon }
364775923a8SSascha Wildner if (abstime == NULL ||
365fcaa7a3aSMatthew Dillon abstime->tv_nsec >= 1000000000 ||
366fcaa7a3aSMatthew Dillon abstime->tv_nsec < 0) {
36798247283SMatthew Dillon sem_log("sem_wait %p %d (bad abstime)\n", *sem, val);
36871b3fa15SDavid Xu errno = EINVAL;
36971b3fa15SDavid Xu return (-1);
37071b3fa15SDavid Xu }
37171b3fa15SDavid Xu clock_gettime(CLOCK_REALTIME, &ts);
372ce96aca2SSascha Wildner timespecsub(abstime, &ts, &ts2);
37371b3fa15SDavid Xu oldcancel = _thr_cancel_enter(curthread);
37498247283SMatthew Dillon sem_log("sem_wait %p %d (wait)\n", *sem, val);
3759219c44cSDavid Xu retval = _thr_umtx_wait(&(*sem)->count, 0, &ts2,
3769219c44cSDavid Xu CLOCK_REALTIME);
37798247283SMatthew Dillon sem_log("sem_wait %p %d (wait return %d)\n",
37898247283SMatthew Dillon *sem, (*sem)->count, retval);
37971b3fa15SDavid Xu _thr_cancel_leave(curthread, oldcancel);
380fcaa7a3aSMatthew Dillon } while (retval != ETIMEDOUT && retval != EINTR);
381fcaa7a3aSMatthew Dillon
38298247283SMatthew Dillon sem_log("sem_wait %p %d (error %d)\n", *sem, retval);
38371b3fa15SDavid Xu errno = retval;
384fcaa7a3aSMatthew Dillon
38571b3fa15SDavid Xu return (-1);
38671b3fa15SDavid Xu }
38771b3fa15SDavid Xu
38871b3fa15SDavid Xu int
_sem_post(sem_t * sem)38971b3fa15SDavid Xu _sem_post(sem_t *sem)
39071b3fa15SDavid Xu {
39171b3fa15SDavid Xu int val;
39271b3fa15SDavid Xu
39371b3fa15SDavid Xu if (sem_check_validity(sem) != 0)
39471b3fa15SDavid Xu return (-1);
39571b3fa15SDavid Xu
39671b3fa15SDavid Xu /*
39771b3fa15SDavid Xu * sem_post() is required to be safe to call from within
39871b3fa15SDavid Xu * signal handlers, these code should work as that.
39971b3fa15SDavid Xu */
40098247283SMatthew Dillon val = atomic_fetchadd_int(&(*sem)->count, 1) + 1;
40198247283SMatthew Dillon sem_log("sem_post %p %d\n", *sem, val);
40298247283SMatthew Dillon _thr_umtx_wake(&(*sem)->count, 0);
40398247283SMatthew Dillon
40471b3fa15SDavid Xu return (0);
40571b3fa15SDavid Xu }
4065a1048c8SDavid Xu
4071a09a5c7SJoris Giovannangeli static int
get_path(const char * name,char * path,size_t len,char const ** prefix)4081a09a5c7SJoris Giovannangeli get_path(const char *name, char *path, size_t len, char const **prefix)
40986926582SVenkatesh Srinivas {
4101a09a5c7SJoris Giovannangeli size_t path_len;
4111a09a5c7SJoris Giovannangeli
4121a09a5c7SJoris Giovannangeli *prefix = NULL;
4131a09a5c7SJoris Giovannangeli
4141a09a5c7SJoris Giovannangeli if (name[0] == '/') {
4151a09a5c7SJoris Giovannangeli *prefix = getenv("LIBTHREAD_SEM_PREFIX");
4161a09a5c7SJoris Giovannangeli
4171a09a5c7SJoris Giovannangeli if (*prefix == NULL)
4181a09a5c7SJoris Giovannangeli *prefix = sem_prefix;
4191a09a5c7SJoris Giovannangeli
4201a09a5c7SJoris Giovannangeli path_len = strlcpy(path, *prefix, len);
4211a09a5c7SJoris Giovannangeli
4221a09a5c7SJoris Giovannangeli if (path_len > len) {
4231a09a5c7SJoris Giovannangeli return (ENAMETOOLONG);
4241a09a5c7SJoris Giovannangeli }
4251a09a5c7SJoris Giovannangeli }
4261a09a5c7SJoris Giovannangeli
4271a09a5c7SJoris Giovannangeli path_len = strlcat(path, name, len);
4281a09a5c7SJoris Giovannangeli
4291a09a5c7SJoris Giovannangeli if (path_len > len)
4301a09a5c7SJoris Giovannangeli return (ENAMETOOLONG);
4311a09a5c7SJoris Giovannangeli
4321a09a5c7SJoris Giovannangeli return (0);
4331a09a5c7SJoris Giovannangeli }
4341a09a5c7SJoris Giovannangeli
4351a09a5c7SJoris Giovannangeli
4361a09a5c7SJoris Giovannangeli static sem_t *
sem_get_mapping(ino_t inode,dev_t dev)4371a09a5c7SJoris Giovannangeli sem_get_mapping(ino_t inode, dev_t dev)
4381a09a5c7SJoris Giovannangeli {
4391a09a5c7SJoris Giovannangeli struct sem_info *ni;
4401a09a5c7SJoris Giovannangeli struct stat sbuf;
4411a09a5c7SJoris Giovannangeli
4421a09a5c7SJoris Giovannangeli LIST_FOREACH(ni, &sem_list, next) {
4431a09a5c7SJoris Giovannangeli if (ni->inode == inode && ni->dev == dev) {
4441a09a5c7SJoris Giovannangeli /* Check for races */
4451a09a5c7SJoris Giovannangeli if(_fstat(ni->fd, &sbuf) == 0) {
4461a09a5c7SJoris Giovannangeli if (sbuf.st_nlink > 0) {
4471a09a5c7SJoris Giovannangeli ni->open_count++;
4481a09a5c7SJoris Giovannangeli return (&ni->sem);
4491a09a5c7SJoris Giovannangeli } else {
4501a09a5c7SJoris Giovannangeli ni->inode = 0;
4511a09a5c7SJoris Giovannangeli LIST_REMOVE(ni, next);
4521a09a5c7SJoris Giovannangeli }
4531a09a5c7SJoris Giovannangeli }
4541a09a5c7SJoris Giovannangeli return (SEM_FAILED);
4551a09a5c7SJoris Giovannangeli
4561a09a5c7SJoris Giovannangeli }
4571a09a5c7SJoris Giovannangeli }
4581a09a5c7SJoris Giovannangeli
45986926582SVenkatesh Srinivas return (SEM_FAILED);
46086926582SVenkatesh Srinivas }
46186926582SVenkatesh Srinivas
4621a09a5c7SJoris Giovannangeli
4631a09a5c7SJoris Giovannangeli static sem_t *
sem_add_mapping(ino_t inode,dev_t dev,sem_t sem,int fd)4641a09a5c7SJoris Giovannangeli sem_add_mapping(ino_t inode, dev_t dev, sem_t sem, int fd)
46586926582SVenkatesh Srinivas {
4661a09a5c7SJoris Giovannangeli struct sem_info *ni;
4671a09a5c7SJoris Giovannangeli
468e7bf3f77SMatthew Dillon ni = __malloc(sizeof(struct sem_info));
4691a09a5c7SJoris Giovannangeli if (ni == NULL) {
4701a09a5c7SJoris Giovannangeli errno = ENOSPC;
4711a09a5c7SJoris Giovannangeli return (SEM_FAILED);
4721a09a5c7SJoris Giovannangeli }
4731a09a5c7SJoris Giovannangeli
4741a09a5c7SJoris Giovannangeli bzero(ni, sizeof(*ni));
4751a09a5c7SJoris Giovannangeli ni->open_count = 1;
4761a09a5c7SJoris Giovannangeli ni->sem = sem;
4771a09a5c7SJoris Giovannangeli ni->fd = fd;
4781a09a5c7SJoris Giovannangeli ni->inode = inode;
4791a09a5c7SJoris Giovannangeli ni->dev = dev;
4801a09a5c7SJoris Giovannangeli
4811a09a5c7SJoris Giovannangeli LIST_INSERT_HEAD(&sem_list, ni, next);
4821a09a5c7SJoris Giovannangeli
4831a09a5c7SJoris Giovannangeli return (&ni->sem);
4841a09a5c7SJoris Giovannangeli }
4851a09a5c7SJoris Giovannangeli
4861a09a5c7SJoris Giovannangeli static int
sem_close_mapping(sem_t * sem)4871a09a5c7SJoris Giovannangeli sem_close_mapping(sem_t *sem)
4881a09a5c7SJoris Giovannangeli {
4891a09a5c7SJoris Giovannangeli struct sem_info *ni;
4901a09a5c7SJoris Giovannangeli
4911a09a5c7SJoris Giovannangeli if ((*sem)->semid != SEMID_NAMED)
4921a09a5c7SJoris Giovannangeli return (EINVAL);
4931a09a5c7SJoris Giovannangeli
4941a09a5c7SJoris Giovannangeli ni = container_of(sem, struct sem_info, sem);
4951a09a5c7SJoris Giovannangeli
4961a09a5c7SJoris Giovannangeli if ( --ni->open_count > 0) {
4971a09a5c7SJoris Giovannangeli return (0);
4981a09a5c7SJoris Giovannangeli } else {
4991a09a5c7SJoris Giovannangeli if (ni->inode != 0) {
5001a09a5c7SJoris Giovannangeli LIST_REMOVE(ni, next);
5011a09a5c7SJoris Giovannangeli }
5021a09a5c7SJoris Giovannangeli munmap(ni->sem, getpagesize());
5031a09a5c7SJoris Giovannangeli __sys_close(ni->fd);
504e7bf3f77SMatthew Dillon __free(ni);
5051a09a5c7SJoris Giovannangeli return (0);
5061a09a5c7SJoris Giovannangeli }
5071a09a5c7SJoris Giovannangeli }
5081a09a5c7SJoris Giovannangeli
5091a09a5c7SJoris Giovannangeli sem_t *
_sem_open(const char * name,int oflag,...)5101a09a5c7SJoris Giovannangeli _sem_open(const char *name, int oflag, ...)
5111a09a5c7SJoris Giovannangeli {
5121a09a5c7SJoris Giovannangeli char path[PATH_MAX];
5131a09a5c7SJoris Giovannangeli char tmppath[PATH_MAX];
5141a09a5c7SJoris Giovannangeli char const *prefix = NULL;
5151a09a5c7SJoris Giovannangeli size_t path_len;
5161a09a5c7SJoris Giovannangeli int error, fd, create;
5171a09a5c7SJoris Giovannangeli sem_t *sem;
5181a09a5c7SJoris Giovannangeli sem_t semtmp;
5191a09a5c7SJoris Giovannangeli va_list ap;
5201a09a5c7SJoris Giovannangeli mode_t mode;
5211a09a5c7SJoris Giovannangeli struct stat sbuf;
5221a09a5c7SJoris Giovannangeli unsigned int value = 0;
5231a09a5c7SJoris Giovannangeli
5241a09a5c7SJoris Giovannangeli create = 0;
5251a09a5c7SJoris Giovannangeli error = 0;
5261a09a5c7SJoris Giovannangeli fd = -1;
5271a09a5c7SJoris Giovannangeli sem = SEM_FAILED;
5281a09a5c7SJoris Giovannangeli
5290be02bbdSNicolas Thery /*
5300be02bbdSNicolas Thery * Bail out if invalid flags specified.
5310be02bbdSNicolas Thery */
5320be02bbdSNicolas Thery if (oflag & ~(O_CREAT|O_EXCL)) {
5330be02bbdSNicolas Thery errno = EINVAL;
5340be02bbdSNicolas Thery return (SEM_FAILED);
5350be02bbdSNicolas Thery }
5360be02bbdSNicolas Thery
5371a09a5c7SJoris Giovannangeli oflag |= O_RDWR;
5381a09a5c7SJoris Giovannangeli oflag |= O_CLOEXEC;
5391a09a5c7SJoris Giovannangeli
5401a09a5c7SJoris Giovannangeli if (name == NULL) {
5411a09a5c7SJoris Giovannangeli errno = EINVAL;
5421a09a5c7SJoris Giovannangeli return (SEM_FAILED);
5431a09a5c7SJoris Giovannangeli }
5441a09a5c7SJoris Giovannangeli
5451a09a5c7SJoris Giovannangeli _pthread_mutex_lock(&sem_lock);
5461a09a5c7SJoris Giovannangeli
5471a09a5c7SJoris Giovannangeli error = get_path(name, path, PATH_MAX, &prefix);
5481a09a5c7SJoris Giovannangeli if (error) {
5491a09a5c7SJoris Giovannangeli errno = error;
5501a09a5c7SJoris Giovannangeli goto error;
5511a09a5c7SJoris Giovannangeli }
5521a09a5c7SJoris Giovannangeli
5531a09a5c7SJoris Giovannangeli retry:
5541a09a5c7SJoris Giovannangeli fd = __sys_open(path, O_RDWR | O_CLOEXEC);
5551a09a5c7SJoris Giovannangeli
5561a09a5c7SJoris Giovannangeli if (fd > 0) {
5571a09a5c7SJoris Giovannangeli
5581a09a5c7SJoris Giovannangeli if ((oflag & O_EXCL) == O_EXCL) {
5591a09a5c7SJoris Giovannangeli __sys_close(fd);
5601a09a5c7SJoris Giovannangeli errno = EEXIST;
5611a09a5c7SJoris Giovannangeli goto error;
5621a09a5c7SJoris Giovannangeli }
5631a09a5c7SJoris Giovannangeli
5641a09a5c7SJoris Giovannangeli if (_fstat(fd, &sbuf) != 0) {
5651a09a5c7SJoris Giovannangeli /* Bad things happened, like another thread closing our descriptor */
5661a09a5c7SJoris Giovannangeli __sys_close(fd);
5671a09a5c7SJoris Giovannangeli errno = EINVAL;
5681a09a5c7SJoris Giovannangeli goto error;
5691a09a5c7SJoris Giovannangeli }
5701a09a5c7SJoris Giovannangeli
5711a09a5c7SJoris Giovannangeli sem = sem_get_mapping(sbuf.st_ino, sbuf.st_dev);
5721a09a5c7SJoris Giovannangeli
5731a09a5c7SJoris Giovannangeli if (sem != SEM_FAILED) {
5741a09a5c7SJoris Giovannangeli __sys_close(fd);
5751a09a5c7SJoris Giovannangeli goto done;
5761a09a5c7SJoris Giovannangeli }
5771a09a5c7SJoris Giovannangeli
5781a09a5c7SJoris Giovannangeli if ((sbuf.st_mode & S_IFREG) == 0) {
5791a09a5c7SJoris Giovannangeli /* We only want regular files here */
5801a09a5c7SJoris Giovannangeli __sys_close(fd);
5811a09a5c7SJoris Giovannangeli errno = EINVAL;
5821a09a5c7SJoris Giovannangeli goto error;
5831a09a5c7SJoris Giovannangeli }
5841a09a5c7SJoris Giovannangeli } else if ((oflag & O_CREAT) && errno == ENOENT) {
5851a09a5c7SJoris Giovannangeli
5861a09a5c7SJoris Giovannangeli va_start(ap, oflag);
5871a09a5c7SJoris Giovannangeli
5881a09a5c7SJoris Giovannangeli mode = (mode_t) va_arg(ap, int);
5891a09a5c7SJoris Giovannangeli value = (unsigned int) va_arg(ap, int);
5901a09a5c7SJoris Giovannangeli
5911a09a5c7SJoris Giovannangeli va_end(ap);
5921a09a5c7SJoris Giovannangeli
5931a09a5c7SJoris Giovannangeli if (value > SEM_VALUE_MAX) {
5941a09a5c7SJoris Giovannangeli errno = EINVAL;
5951a09a5c7SJoris Giovannangeli goto error;
5961a09a5c7SJoris Giovannangeli }
5971a09a5c7SJoris Giovannangeli
5981a09a5c7SJoris Giovannangeli strlcpy(tmppath, prefix, sizeof(tmppath));
5991a09a5c7SJoris Giovannangeli path_len = strlcat(tmppath, "/sem.XXXXXX", sizeof(tmppath));
6001a09a5c7SJoris Giovannangeli
6011a09a5c7SJoris Giovannangeli if (path_len > sizeof(tmppath)) {
6021a09a5c7SJoris Giovannangeli errno = ENAMETOOLONG;
6031a09a5c7SJoris Giovannangeli goto error;
6041a09a5c7SJoris Giovannangeli }
6051a09a5c7SJoris Giovannangeli
6061a09a5c7SJoris Giovannangeli
60792d9bb5eSJohannes Hofmann fd = mkstemp(tmppath);
60892d9bb5eSJohannes Hofmann
60992d9bb5eSJohannes Hofmann if ( fd == -1 ) {
6101a09a5c7SJoris Giovannangeli errno = EINVAL;
6111a09a5c7SJoris Giovannangeli goto error;
6121a09a5c7SJoris Giovannangeli }
6131a09a5c7SJoris Giovannangeli
61492d9bb5eSJohannes Hofmann error = fchmod(fd, mode);
61592d9bb5eSJohannes Hofmann if ( error == -1 ) {
6161a09a5c7SJoris Giovannangeli __sys_close(fd);
61792d9bb5eSJohannes Hofmann errno = EINVAL;
61892d9bb5eSJohannes Hofmann goto error;
61992d9bb5eSJohannes Hofmann }
62092d9bb5eSJohannes Hofmann
62192d9bb5eSJohannes Hofmann error = __sys_fcntl(fd, F_SETFD, FD_CLOEXEC);
62292d9bb5eSJohannes Hofmann if ( error == -1 ) {
62392d9bb5eSJohannes Hofmann __sys_close(fd);
62492d9bb5eSJohannes Hofmann errno = EINVAL;
6251a09a5c7SJoris Giovannangeli goto error;
6261a09a5c7SJoris Giovannangeli }
6271a09a5c7SJoris Giovannangeli
6281a09a5c7SJoris Giovannangeli create = 1;
6291a09a5c7SJoris Giovannangeli }
6301a09a5c7SJoris Giovannangeli
6311a09a5c7SJoris Giovannangeli if (fd == -1) {
6321a09a5c7SJoris Giovannangeli switch (errno) {
6331a09a5c7SJoris Giovannangeli case ENOTDIR:
6341a09a5c7SJoris Giovannangeli case EISDIR:
6351a09a5c7SJoris Giovannangeli case EMLINK:
6361a09a5c7SJoris Giovannangeli case ELOOP:
6371a09a5c7SJoris Giovannangeli errno = EINVAL;
6381a09a5c7SJoris Giovannangeli break;
6391a09a5c7SJoris Giovannangeli case EDQUOT:
6401a09a5c7SJoris Giovannangeli case EIO:
6411a09a5c7SJoris Giovannangeli errno = ENOSPC;
6421a09a5c7SJoris Giovannangeli break;
6431a09a5c7SJoris Giovannangeli case EROFS:
6441a09a5c7SJoris Giovannangeli errno = EACCES;
6451a09a5c7SJoris Giovannangeli }
6461a09a5c7SJoris Giovannangeli goto error;
6471a09a5c7SJoris Giovannangeli }
6481a09a5c7SJoris Giovannangeli
6491a09a5c7SJoris Giovannangeli semtmp = (sem_t) mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE,
6501a09a5c7SJoris Giovannangeli MAP_NOSYNC | MAP_SHARED, fd, 0);
6511a09a5c7SJoris Giovannangeli
6521a09a5c7SJoris Giovannangeli if (semtmp == MAP_FAILED) {
6531a09a5c7SJoris Giovannangeli if (errno != EACCES && errno != EMFILE)
6541a09a5c7SJoris Giovannangeli errno = ENOMEM;
6551a09a5c7SJoris Giovannangeli
6561a09a5c7SJoris Giovannangeli if (create)
65711699d20SMatthew Dillon _unlink(tmppath);
6581a09a5c7SJoris Giovannangeli
6591a09a5c7SJoris Giovannangeli __sys_close(fd);
6601a09a5c7SJoris Giovannangeli goto error;
6611a09a5c7SJoris Giovannangeli }
6621a09a5c7SJoris Giovannangeli
6631a09a5c7SJoris Giovannangeli if (create) {
6641a09a5c7SJoris Giovannangeli ftruncate(fd, sizeof(struct sem));
6651a09a5c7SJoris Giovannangeli semtmp->magic = SEM_MAGIC;
6661a09a5c7SJoris Giovannangeli semtmp->count = (u_int32_t)value;
6671a09a5c7SJoris Giovannangeli semtmp->semid = SEMID_NAMED;
6681a09a5c7SJoris Giovannangeli
66992d9bb5eSJohannes Hofmann if (link(tmppath, path) != 0) {
6701a09a5c7SJoris Giovannangeli munmap(semtmp, getpagesize());
6711a09a5c7SJoris Giovannangeli __sys_close(fd);
67211699d20SMatthew Dillon _unlink(tmppath);
6731a09a5c7SJoris Giovannangeli
6741a09a5c7SJoris Giovannangeli if (errno == EEXIST && (oflag & O_EXCL) == 0) {
6751a09a5c7SJoris Giovannangeli goto retry;
6761a09a5c7SJoris Giovannangeli }
6771a09a5c7SJoris Giovannangeli
6781a09a5c7SJoris Giovannangeli goto error;
6791a09a5c7SJoris Giovannangeli }
68011699d20SMatthew Dillon _unlink(tmppath);
6811a09a5c7SJoris Giovannangeli
6821a09a5c7SJoris Giovannangeli if (_fstat(fd, &sbuf) != 0) {
6831a09a5c7SJoris Giovannangeli /* Bad things happened, like another thread closing our descriptor */
6841a09a5c7SJoris Giovannangeli munmap(semtmp, getpagesize());
6851a09a5c7SJoris Giovannangeli __sys_close(fd);
6861a09a5c7SJoris Giovannangeli errno = EINVAL;
6871a09a5c7SJoris Giovannangeli goto error;
6881a09a5c7SJoris Giovannangeli }
6891a09a5c7SJoris Giovannangeli
6901a09a5c7SJoris Giovannangeli }
6911a09a5c7SJoris Giovannangeli sem = sem_add_mapping(sbuf.st_ino, sbuf.st_dev, semtmp, fd);
6921a09a5c7SJoris Giovannangeli
6931a09a5c7SJoris Giovannangeli done:
6941a09a5c7SJoris Giovannangeli _pthread_mutex_unlock(&sem_lock);
6951a09a5c7SJoris Giovannangeli return (sem);
6961a09a5c7SJoris Giovannangeli
6971a09a5c7SJoris Giovannangeli error:
6981a09a5c7SJoris Giovannangeli _pthread_mutex_unlock(&sem_lock);
6991a09a5c7SJoris Giovannangeli return (SEM_FAILED);
7001a09a5c7SJoris Giovannangeli
70186926582SVenkatesh Srinivas }
70286926582SVenkatesh Srinivas
70386926582SVenkatesh Srinivas int
_sem_close(sem_t * sem)7041a09a5c7SJoris Giovannangeli _sem_close(sem_t *sem)
70586926582SVenkatesh Srinivas {
7061a09a5c7SJoris Giovannangeli _pthread_mutex_lock(&sem_lock);
7071a09a5c7SJoris Giovannangeli
7081a09a5c7SJoris Giovannangeli if (sem_check_validity(sem)) {
7091a09a5c7SJoris Giovannangeli _pthread_mutex_unlock(&sem_lock);
7101a09a5c7SJoris Giovannangeli errno = EINVAL;
71186926582SVenkatesh Srinivas return (-1);
71286926582SVenkatesh Srinivas }
71386926582SVenkatesh Srinivas
7141a09a5c7SJoris Giovannangeli if (sem_close_mapping(sem)) {
7151a09a5c7SJoris Giovannangeli _pthread_mutex_unlock(&sem_lock);
7161a09a5c7SJoris Giovannangeli errno = EINVAL;
7171a09a5c7SJoris Giovannangeli return (-1);
7181a09a5c7SJoris Giovannangeli }
7191a09a5c7SJoris Giovannangeli _pthread_mutex_unlock(&sem_lock);
7201a09a5c7SJoris Giovannangeli
7211a09a5c7SJoris Giovannangeli return (0);
7221a09a5c7SJoris Giovannangeli }
7231a09a5c7SJoris Giovannangeli
7241a09a5c7SJoris Giovannangeli int
_sem_unlink(const char * name)7251a09a5c7SJoris Giovannangeli _sem_unlink(const char *name)
7261a09a5c7SJoris Giovannangeli {
7271a09a5c7SJoris Giovannangeli char path[PATH_MAX];
7281a09a5c7SJoris Giovannangeli const char *prefix;
7291a09a5c7SJoris Giovannangeli int error;
7301a09a5c7SJoris Giovannangeli
7311a09a5c7SJoris Giovannangeli error = get_path(name, path, PATH_MAX, &prefix);
7321a09a5c7SJoris Giovannangeli if (error) {
7331a09a5c7SJoris Giovannangeli errno = error;
7341a09a5c7SJoris Giovannangeli return (-1);
7351a09a5c7SJoris Giovannangeli }
7361a09a5c7SJoris Giovannangeli
73711699d20SMatthew Dillon error = _unlink(path);
7381a09a5c7SJoris Giovannangeli
7391a09a5c7SJoris Giovannangeli if(error) {
7401a09a5c7SJoris Giovannangeli if (errno != ENAMETOOLONG && errno != ENOENT)
7411a09a5c7SJoris Giovannangeli errno = EACCES;
7421a09a5c7SJoris Giovannangeli
7431a09a5c7SJoris Giovannangeli return (-1);
7441a09a5c7SJoris Giovannangeli }
7451a09a5c7SJoris Giovannangeli
7461a09a5c7SJoris Giovannangeli return (0);
7471a09a5c7SJoris Giovannangeli }
7481a09a5c7SJoris Giovannangeli
7495a1048c8SDavid Xu __strong_reference(_sem_destroy, sem_destroy);
7505a1048c8SDavid Xu __strong_reference(_sem_getvalue, sem_getvalue);
7515a1048c8SDavid Xu __strong_reference(_sem_init, sem_init);
7525a1048c8SDavid Xu __strong_reference(_sem_trywait, sem_trywait);
7535a1048c8SDavid Xu __strong_reference(_sem_wait, sem_wait);
7545a1048c8SDavid Xu __strong_reference(_sem_timedwait, sem_timedwait);
7555a1048c8SDavid Xu __strong_reference(_sem_post, sem_post);
75686926582SVenkatesh Srinivas __strong_reference(_sem_open, sem_open);
75786926582SVenkatesh Srinivas __strong_reference(_sem_close, sem_close);
75886926582SVenkatesh Srinivas __strong_reference(_sem_unlink, sem_unlink);
759