| Index: fusl/src/thread/sem_open.c | 
| diff --git a/fusl/src/thread/sem_open.c b/fusl/src/thread/sem_open.c | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..fda0acd35c717992e44b4c5191e6f400d1190532 | 
| --- /dev/null | 
| +++ b/fusl/src/thread/sem_open.c | 
| @@ -0,0 +1,175 @@ | 
| +#include <semaphore.h> | 
| +#include <sys/mman.h> | 
| +#include <limits.h> | 
| +#include <fcntl.h> | 
| +#include <unistd.h> | 
| +#include <string.h> | 
| +#include <stdarg.h> | 
| +#include <errno.h> | 
| +#include <time.h> | 
| +#include <stdio.h> | 
| +#include <sys/stat.h> | 
| +#include <stdlib.h> | 
| +#include <pthread.h> | 
| +#include "libc.h" | 
| + | 
| +char *__shm_mapname(const char *, char *); | 
| + | 
| +static struct { | 
| +	ino_t ino; | 
| +	sem_t *sem; | 
| +	int refcnt; | 
| +} *semtab; | 
| +static volatile int lock[2]; | 
| + | 
| +#define FLAGS (O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NONBLOCK) | 
| + | 
| +sem_t *sem_open(const char *name, int flags, ...) | 
| +{ | 
| +	va_list ap; | 
| +	mode_t mode; | 
| +	unsigned value; | 
| +	int fd, i, e, slot, first=1, cnt, cs; | 
| +	sem_t newsem; | 
| +	void *map; | 
| +	char tmp[64]; | 
| +	struct timespec ts; | 
| +	struct stat st; | 
| +	char buf[NAME_MAX+10]; | 
| + | 
| +	if (!(name = __shm_mapname(name, buf))) | 
| +		return SEM_FAILED; | 
| + | 
| +	LOCK(lock); | 
| +	/* Allocate table if we don't have one yet */ | 
| +	if (!semtab && !(semtab = calloc(sizeof *semtab, SEM_NSEMS_MAX))) { | 
| +		UNLOCK(lock); | 
| +		return SEM_FAILED; | 
| +	} | 
| + | 
| +	/* Reserve a slot in case this semaphore is not mapped yet; | 
| +	 * this is necessary because there is no way to handle | 
| +	 * failures after creation of the file. */ | 
| +	slot = -1; | 
| +	for (cnt=i=0; i<SEM_NSEMS_MAX; i++) { | 
| +		cnt += semtab[i].refcnt; | 
| +		if (!semtab[i].sem && slot < 0) slot = i; | 
| +	} | 
| +	/* Avoid possibility of overflow later */ | 
| +	if (cnt == INT_MAX || slot < 0) { | 
| +		errno = EMFILE; | 
| +		UNLOCK(lock); | 
| +		return SEM_FAILED; | 
| +	} | 
| +	/* Dummy pointer to make a reservation */ | 
| +	semtab[slot].sem = (sem_t *)-1; | 
| +	UNLOCK(lock); | 
| + | 
| +	flags &= (O_CREAT|O_EXCL); | 
| + | 
| +	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); | 
| + | 
| +	/* Early failure check for exclusive open; otherwise the case | 
| +	 * where the semaphore already exists is expensive. */ | 
| +	if (flags == (O_CREAT|O_EXCL) && access(name, F_OK) == 0) { | 
| +		errno = EEXIST; | 
| +		goto fail; | 
| +	} | 
| + | 
| +	for (;;) { | 
| +		/* If exclusive mode is not requested, try opening an | 
| +		 * existing file first and fall back to creation. */ | 
| +		if (flags != (O_CREAT|O_EXCL)) { | 
| +			fd = open(name, FLAGS); | 
| +			if (fd >= 0) { | 
| +				if (fstat(fd, &st) < 0 || | 
| +				    (map = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { | 
| +					close(fd); | 
| +					goto fail; | 
| +				} | 
| +				close(fd); | 
| +				break; | 
| +			} | 
| +			if (errno != ENOENT) | 
| +				goto fail; | 
| +		} | 
| +		if (!(flags & O_CREAT)) | 
| +			goto fail; | 
| +		if (first) { | 
| +			first = 0; | 
| +			va_start(ap, flags); | 
| +			mode = va_arg(ap, mode_t) & 0666; | 
| +			value = va_arg(ap, unsigned); | 
| +			va_end(ap); | 
| +			if (value > SEM_VALUE_MAX) { | 
| +				errno = EINVAL; | 
| +				goto fail; | 
| +			} | 
| +			sem_init(&newsem, 1, value); | 
| +		} | 
| +		/* Create a temp file with the new semaphore contents | 
| +		 * and attempt to atomically link it as the new name */ | 
| +		clock_gettime(CLOCK_REALTIME, &ts); | 
| +		snprintf(tmp, sizeof(tmp), "/dev/shm/tmp-%d", (int)ts.tv_nsec); | 
| +		fd = open(tmp, O_CREAT|O_EXCL|FLAGS, mode); | 
| +		if (fd < 0) { | 
| +			if (errno == EEXIST) continue; | 
| +			goto fail; | 
| +		} | 
| +		if (write(fd, &newsem, sizeof newsem) != sizeof newsem || fstat(fd, &st) < 0 || | 
| +		    (map = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { | 
| +			close(fd); | 
| +			unlink(tmp); | 
| +			goto fail; | 
| +		} | 
| +		close(fd); | 
| +		e = link(tmp, name) ? errno : 0; | 
| +		unlink(tmp); | 
| +		if (!e) break; | 
| +		munmap(map, sizeof(sem_t)); | 
| +		/* Failure is only fatal when doing an exclusive open; | 
| +		 * otherwise, next iteration will try to open the | 
| +		 * existing file. */ | 
| +		if (e != EEXIST || flags == (O_CREAT|O_EXCL)) | 
| +			goto fail; | 
| +	} | 
| + | 
| +	/* See if the newly mapped semaphore is already mapped. If | 
| +	 * so, unmap the new mapping and use the existing one. Otherwise, | 
| +	 * add it to the table of mapped semaphores. */ | 
| +	LOCK(lock); | 
| +	for (i=0; i<SEM_NSEMS_MAX && semtab[i].ino != st.st_ino; i++); | 
| +	if (i<SEM_NSEMS_MAX) { | 
| +		munmap(map, sizeof(sem_t)); | 
| +		semtab[slot].sem = 0; | 
| +		slot = i; | 
| +		map = semtab[i].sem; | 
| +	} | 
| +	semtab[slot].refcnt++; | 
| +	semtab[slot].sem = map; | 
| +	semtab[slot].ino = st.st_ino; | 
| +	UNLOCK(lock); | 
| +	pthread_setcancelstate(cs, 0); | 
| +	return map; | 
| + | 
| +fail: | 
| +	pthread_setcancelstate(cs, 0); | 
| +	LOCK(lock); | 
| +	semtab[slot].sem = 0; | 
| +	UNLOCK(lock); | 
| +	return SEM_FAILED; | 
| +} | 
| + | 
| +int sem_close(sem_t *sem) | 
| +{ | 
| +	int i; | 
| +	LOCK(lock); | 
| +	for (i=0; i<SEM_NSEMS_MAX && semtab[i].sem != sem; i++); | 
| +	if (!--semtab[i].refcnt) { | 
| +		semtab[i].sem = 0; | 
| +		semtab[i].ino = 0; | 
| +	} | 
| +	UNLOCK(lock); | 
| +	munmap(sem, sizeof *sem); | 
| +	return 0; | 
| +} | 
|  |