xref: /dflybsd-src/lib/libthread_xu/thread/thr_sem.c (revision 940be950819fa932cd401a01f1182bf686a2e61e)
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