Index: include/Makefile =================================================================== --- include/Makefile (revision 200821) +++ include/Makefile (working copy) @@ -18,7 +18,7 @@ netdb.h nl_types.h nlist.h nss.h nsswitch.h paths.h \ printf.h proc_service.h pthread.h \ pthread_np.h pwd.h ranlib.h readpassphrase.h regex.h regexp.h \ - res_update.h resolv.h runetype.h search.h setjmp.h \ + res_update.h resolv.h runetype.h search.h semaphore.h setjmp.h \ signal.h spawn.h stab.h \ stdbool.h stddef.h stdio.h stdlib.h string.h stringlist.h \ strings.h sysexits.h tar.h termios.h tgmath.h \ @@ -28,7 +28,7 @@ MHDRS= float.h floatingpoint.h stdarg.h -PHDRS= sched.h semaphore.h _semaphore.h +PHDRS= sched.h _semaphore.h LHDRS= aio.h errno.h fcntl.h linker_set.h poll.h stdint.h syslog.h \ ucontext.h Index: include/semaphore.h =================================================================== --- include/semaphore.h (revision 0) +++ include/semaphore.h (revision 0) @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010 David Xu + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* semaphore.h: POSIX 1003.1b semaphores */ + +#ifndef _SEMAPHORE_H_ +#define _SEMAPHORE_H_ + +#include +#include +#include + +struct _sem { + __uint32_t _magic; + struct _usem _kern; +}; + +typedef struct _sem sem_t; + +#define SEM_FAILED ((sem_t *)0) +#define SEM_VALUE_MAX __INT_MAX + +struct timespec; + +__BEGIN_DECLS +int sem_close(sem_t *); +int sem_destroy(sem_t *); +int sem_getvalue(sem_t * __restrict, int * __restrict); +int sem_init(sem_t *, int, unsigned int); +sem_t *sem_open(const char *, int, ...); +int sem_post(sem_t *); +int sem_timedwait(sem_t * __restrict, const struct timespec * __restrict); +int sem_trywait(sem_t *); +int sem_unlink(const char *); +int sem_wait(sem_t *); +__END_DECLS + +#endif /* !_SEMAPHORE_H_ */ Index: lib/libc/gen/sem.c =================================================================== --- lib/libc/gen/sem.c (revision 200821) +++ lib/libc/gen/sem.c (working copy) @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000 Jason Evans . + * Copyright (C) 2010 David Xu . * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,333 +29,438 @@ * $FreeBSD$ */ -/* - * Some notes about this implementation. - * - * This is mostly a simple implementation of POSIX semaphores that - * does not need threading. Any semaphore created is a kernel-based - * semaphore regardless of the pshared attribute. This is necessary - * because libc's stub for pthread_cond_wait() doesn't really wait, - * and it is not worth the effort impose this behavior on libc. - * - * All functions here are designed to be thread-safe so that a - * threads library need not provide wrappers except to make - * sem_wait() and sem_timedwait() cancellation points or to - * provide a faster userland implementation for non-pshared - * semaphores. - * - * Also, this implementation of semaphores cannot really support - * real pshared semaphores. The sem_t is an allocated object - * and can't be seen by other processes when placed in shared - * memory. It should work across forks as long as the semaphore - * is created before any forks. - * - * The function sem_init() should be overridden by a threads - * library if it wants to provide a different userland version - * of semaphores. The functions sem_wait() and sem_timedwait() - * need to be wrapped to provide cancellation points. The function - * sem_post() may need to be wrapped to be signal-safe. - */ #include "namespace.h" #include +#include #include +#include +#include #include +#include +#include #include #include -#include #include #include +#include #include -#include <_semaphore.h> +#include +#include #include "un-namespace.h" -#include "libc_private.h" -static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); -static void sem_free(sem_t sem); +__weak_reference(_libc_sem_close, sem_close); +__weak_reference(_libc_sem_close, _sem_close); +__weak_reference(_libc_sem_destroy, sem_destroy); +__weak_reference(_libc_sem_destroy, _sem_destroy); +__weak_reference(_libc_sem_getvalue, sem_getvalue); +__weak_reference(_libc_sem_getvalue, _sem_getvalue); +__weak_reference(_libc_sem_init, sem_init); +__weak_reference(_libc_sem_init, _sem_init); +__weak_reference(_libc_sem_open, sem_open); +__weak_reference(_libc_sem_open, _sem_open); +__weak_reference(_libc_sem_post, sem_post); +__weak_reference(_libc_sem_post, _sem_post); +__weak_reference(_libc_sem_timedwait, sem_timedwait); +__weak_reference(_libc_sem_timedwait, _sem_timedwait); +__weak_reference(_libc_sem_trywait, sem_trywait); +__weak_reference(_libc_sem_trywait, _sem_trywait); +__weak_reference(_libc_sem_unlink, sem_unlink); +__weak_reference(_libc_sem_unlink, _sem_unlink); +__weak_reference(_libc_sem_wait, sem_wait); +__weak_reference(_libc_sem_wait, _sem_wait); -static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(&named_sems); -static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER; +#define SEM_PREFIX "/tmp/SEMD" +#define SEM_MAGIC ((u_int32_t)0x73656d31) -__weak_reference(__sem_init, sem_init); -__weak_reference(__sem_destroy, sem_destroy); -__weak_reference(__sem_open, sem_open); -__weak_reference(__sem_close, sem_close); -__weak_reference(__sem_unlink, sem_unlink); -__weak_reference(__sem_wait, sem_wait); -__weak_reference(__sem_trywait, sem_trywait); -__weak_reference(__sem_timedwait, sem_timedwait); -__weak_reference(__sem_post, sem_post); -__weak_reference(__sem_getvalue, sem_getvalue); +struct sem_nameinfo { + int open_count; + char *name; + sem_t *sem; + LIST_ENTRY(sem_nameinfo) next; +}; +static pthread_once_t once = PTHREAD_ONCE_INIT; +static pthread_mutex_t sem_llock; +static LIST_HEAD(,sem_nameinfo) sem_list = LIST_HEAD_INITIALIZER(sem_list); -static inline int -sem_check_validity(sem_t *sem) +static void +sem_prefork() { + + _pthread_mutex_lock(&sem_llock); +} - if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC)) - return (0); - else { - errno = EINVAL; - return (-1); - } +static void +sem_postfork() +{ + _pthread_mutex_unlock(&sem_llock); } static void -sem_free(sem_t sem) +sem_child_postfork() { + _pthread_mutex_unlock(&sem_llock); +} - _pthread_mutex_destroy(&sem->lock); - _pthread_cond_destroy(&sem->gtzero); - sem->magic = 0; - free(sem); +static void +sem_module_init(void) +{ + pthread_mutexattr_t ma; + + _pthread_mutexattr_init(&ma); + _pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE); + _pthread_mutex_init(&sem_llock, &ma); + _pthread_mutexattr_destroy(&ma); + _pthread_atfork(sem_prefork, sem_postfork, sem_child_postfork); } -static sem_t -sem_alloc(unsigned int value, semid_t semid, int system_sem) +static inline int +sem_check_validity(sem_t *sem) { - sem_t sem; - if (value > SEM_VALUE_MAX) { + if (sem->_magic == SEM_MAGIC) + return (0); + else { errno = EINVAL; - return (NULL); + return (-1); } - - sem = (sem_t)malloc(sizeof(struct sem)); - if (sem == NULL) { - errno = ENOSPC; - return (NULL); - } - - sem->count = (u_int32_t)value; - sem->nwaiters = 0; - sem->magic = SEM_MAGIC; - sem->semid = semid; - sem->syssem = system_sem; - sem->lock = PTHREAD_MUTEX_INITIALIZER; - sem->gtzero = PTHREAD_COND_INITIALIZER; - return (sem); } int -__sem_init(sem_t *sem, int pshared, unsigned int value) +_libc_sem_init(sem_t *sem, int pshared, unsigned int value) { - semid_t semid; - /* - * We always have to create the kernel semaphore if the - * threads library isn't present since libc's version of - * pthread_cond_wait() is just a stub that doesn't really - * wait. - */ - if (ksem_init(&semid, value) != 0) + if (value > SEM_VALUE_MAX) { + errno = EINVAL; return (-1); - - (*sem) = sem_alloc(value, semid, 1); - if ((*sem) == NULL) { - ksem_destroy(semid); - return (-1); } + + bzero(sem, sizeof(sem_t)); + sem->_magic = SEM_MAGIC; + sem->_kern._count = (u_int32_t)value; + sem->_kern._has_waiters = 0; + sem->_kern._flags = pshared ? USYNC_PROCESS_SHARED : 0; return (0); } -int -__sem_destroy(sem_t *sem) +sem_t * +_libc_sem_open(const char *name, int flags, ...) { - int retval; + char path[PATH_MAX]; - if (sem_check_validity(sem) != 0) - return (-1); + struct stat sb; + va_list ap; + struct sem_nameinfo *ni = NULL; + sem_t *sem = NULL; + int fd = -1, mode, len; - _pthread_mutex_lock(&(*sem)->lock); - /* - * If this is a system semaphore let the kernel track it otherwise - * make sure there are no waiters. - */ - if ((*sem)->syssem != 0) - retval = ksem_destroy((*sem)->semid); - else if ((*sem)->nwaiters > 0) { - errno = EBUSY; - retval = -1; + if (name[0] != '/') { + errno = EINVAL; + return (NULL); } - else { - retval = 0; - (*sem)->magic = 0; - } - _pthread_mutex_unlock(&(*sem)->lock); + name++; - if (retval == 0) { - _pthread_mutex_destroy(&(*sem)->lock); - _pthread_cond_destroy(&(*sem)->gtzero); - sem_free(*sem); + if (flags & ~(O_CREAT|O_EXCL)) { + errno = EINVAL; + return (NULL); } - return (retval); -} -sem_t * -__sem_open(const char *name, int oflag, ...) -{ - sem_t *sem; - sem_t s; - semid_t semid; - mode_t mode; - unsigned int value; + _pthread_once(&once, sem_module_init); - mode = 0; - value = 0; + _pthread_mutex_lock(&sem_llock); + LIST_FOREACH(ni, &sem_list, next) { + if (strcmp(name, ni->name) == 0) { + ni->open_count++; + sem = ni->sem; + _pthread_mutex_unlock(&sem_llock); + return (sem); + } + } - if ((oflag & O_CREAT) != 0) { - va_list ap; - - va_start(ap, oflag); + if (flags & O_CREAT) { + va_start(ap, flags); mode = va_arg(ap, int); - value = va_arg(ap, unsigned int); va_end(ap); } - /* - * we can be lazy and let the kernel handle the "oflag", - * we'll just merge duplicate IDs into our list. - */ - if (ksem_open(&semid, name, oflag, mode, value) == -1) - return (SEM_FAILED); - /* - * search for a duplicate ID, we must return the same sem_t * - * if we locate one. - */ - _pthread_mutex_lock(&named_sems_mtx); - LIST_FOREACH(s, &named_sems, entry) { - if (s->semid == semid) { - sem = s->backpointer; - _pthread_mutex_unlock(&named_sems_mtx); - return (sem); + + len = sizeof(*ni) + strlen(name) + 1; + ni = (struct sem_nameinfo *)malloc(len); + if (ni == NULL) { + errno = ENOSPC; + goto error; + } + + ni->name = (char *)(ni+1); + strcpy(ni->name, name); + + strcpy(path, SEM_PREFIX); + if (strlcat(path, name, sizeof(path)) >= sizeof(path)) { + errno = ENAMETOOLONG; + goto error; + } + + fd = _open(path, flags|O_RDWR, mode); + if (fd == -1) + goto error; + if (flock(fd, LOCK_EX) == -1) + goto error; + if (_fstat(fd, &sb)) { + flock(fd, LOCK_UN); + goto error; + } + if (sb.st_size < sizeof(sem_t)) { + sem_t tmp; + + tmp._magic = SEM_MAGIC; + tmp._kern._has_waiters = 0; + tmp._kern._count = 0; + tmp._kern._flags = USYNC_PROCESS_SHARED | SEM_NAMED; + if (_write(fd, &tmp, sizeof(tmp)) != sizeof(tmp)) { + flock(fd, LOCK_UN); + goto error; } } - sem = (sem_t *)malloc(sizeof(*sem)); - if (sem == NULL) - goto err; - *sem = sem_alloc(value, semid, 1); - if ((*sem) == NULL) - goto err; - LIST_INSERT_HEAD(&named_sems, *sem, entry); - (*sem)->backpointer = sem; - _pthread_mutex_unlock(&named_sems_mtx); - return (sem); -err: - _pthread_mutex_unlock(&named_sems_mtx); - ksem_close(semid); - if (sem != NULL) { - if (*sem != NULL) - sem_free(*sem); - else + flock(fd, LOCK_UN); + sem = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_NOSYNC, fd, 0); + if (sem == MAP_FAILED) { + sem = NULL; + if (errno == ENOMEM) errno = ENOSPC; - free(sem); - } else { - errno = ENOSPC; + goto error; } + if (sem->_magic != SEM_MAGIC) { + errno = EINVAL; + goto error; + } + ni->open_count = 1; + ni->sem = sem; + LIST_INSERT_HEAD(&sem_list, ni, next); + _pthread_mutex_unlock(&sem_llock); + _close(fd); + return (sem); + +error: + _pthread_mutex_unlock(&sem_llock); + if (fd != -1) + _close(fd); + if (sem != NULL) + munmap(sem, sizeof(sem_t)); + free(ni); return (SEM_FAILED); } int -__sem_close(sem_t *sem) +_libc_sem_close(sem_t *sem) { + struct sem_nameinfo *ni; if (sem_check_validity(sem) != 0) return (-1); - if ((*sem)->syssem == 0) { + if (!(sem->_kern._flags & SEM_NAMED)) { errno = EINVAL; return (-1); } - _pthread_mutex_lock(&named_sems_mtx); - if (ksem_close((*sem)->semid) != 0) { - _pthread_mutex_unlock(&named_sems_mtx); - return (-1); + _pthread_mutex_lock(&sem_llock); + LIST_FOREACH(ni, &sem_list, next) { + if (sem == ni->sem) { + if (--ni->open_count > 0) { + _pthread_mutex_unlock(&sem_llock); + return (0); + } + else + break; + } } - LIST_REMOVE((*sem), entry); - _pthread_mutex_unlock(&named_sems_mtx); - sem_free(*sem); - *sem = NULL; - free(sem); - return (0); + + if (ni) { + LIST_REMOVE(ni, next); + _pthread_mutex_unlock(&sem_llock); + munmap(sem, sizeof(*sem)); + free(ni); + return (0); + } + _pthread_mutex_unlock(&sem_llock); + return (-1); } int -__sem_unlink(const char *name) +_libc_sem_unlink(const char *name) { + char path[PATH_MAX]; - return (ksem_unlink(name)); + if (name[0] != '/') { + errno = ENOENT; + return -1; + } + name++; + + strcpy(path, SEM_PREFIX); + if (strlcat(path, name, sizeof(path)) >= sizeof(path)) { + errno = ENAMETOOLONG; + return (-1); + } + return unlink(path); } int -__sem_wait(sem_t *sem) +_libc_sem_destroy(sem_t *sem) { if (sem_check_validity(sem) != 0) return (-1); - return (ksem_wait((*sem)->semid)); + if (sem->_kern._flags & SEM_NAMED) { + errno = EINVAL; + return (-1); + } + sem->_magic = 0; + return (0); } int -__sem_trywait(sem_t *sem) +_libc_sem_getvalue(sem_t * __restrict sem, int * __restrict sval) { - int retval; if (sem_check_validity(sem) != 0) return (-1); - if ((*sem)->syssem != 0) - retval = ksem_trywait((*sem)->semid); - else { - _pthread_mutex_lock(&(*sem)->lock); - if ((*sem)->count > 0) { - (*sem)->count--; - retval = 0; - } else { - errno = EAGAIN; - retval = -1; - } - _pthread_mutex_unlock(&(*sem)->lock); + *sval = (int)sem->_kern._count; + return (0); +} + +static int +usem_wake(struct _usem *sem) +{ + if (!sem->_has_waiters) + return (0); + return _umtx_op(sem, UMTX_OP_SEM_WAKE, 0, NULL, NULL); +} + +static int +usem_wait(struct _usem *sem, const struct timespec *timeout) +{ + if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 && + timeout->tv_nsec <= 0))) { + errno = ETIMEDOUT; + return (-1); } - return (retval); + return _umtx_op(sem, UMTX_OP_SEM_WAIT, 0, NULL, + __DECONST(void*, timeout)); } int -__sem_timedwait(sem_t * __restrict sem, - const struct timespec * __restrict abs_timeout) +_libc_sem_trywait(sem_t *sem) { + int val; + if (sem_check_validity(sem) != 0) return (-1); - return (ksem_timedwait((*sem)->semid, abs_timeout)); + while ((val = sem->_kern._count) > 0) { + if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1)) + return (0); + } + errno = EAGAIN; + return (-1); } +static void +sem_cancel_handler(void *arg) +{ + sem_t *sem = arg; + + if (sem->_kern._has_waiters && sem->_kern._count) + usem_wake(&sem->_kern); +} + +#define TIMESPEC_SUB(dst, src, val) \ + do { \ + (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \ + (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \ + if ((dst)->tv_nsec < 0) { \ + (dst)->tv_sec--; \ + (dst)->tv_nsec += 1000000000; \ + } \ + } while (0) + + +static int +enable_async_cancel(void) +{ + int old; + + _pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old); + return (old); +} + +static void +restore_async_cancel(int val) +{ + _pthread_setcanceltype(val, NULL); +} + int -__sem_post(sem_t *sem) +_libc_sem_timedwait(sem_t * __restrict sem, + const struct timespec * __restrict abstime) { + struct timespec ts, ts2; + int val, retval, saved_cancel; if (sem_check_validity(sem) != 0) return (-1); - return (ksem_post((*sem)->semid)); + _pthread_testcancel(); + do { + while ((val = sem->_kern._count) > 0) { + if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1)) + return (0); + } + + /* + * The timeout argument is only supposed to + * be checked if the thread would have blocked. + */ + if (abstime != NULL) { + if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) { + errno = EINVAL; + return (-1); + } + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + } + pthread_cleanup_push(sem_cancel_handler, sem); + saved_cancel = enable_async_cancel(); + retval = usem_wait(&sem->_kern, abstime ? &ts2 : NULL); + restore_async_cancel(saved_cancel); + pthread_cleanup_pop(0); + } while (retval == 0); + return (-1); } int -__sem_getvalue(sem_t * __restrict sem, int * __restrict sval) +_libc_sem_wait(sem_t *sem) { - int retval; + return _libc_sem_timedwait(sem, NULL); +} +/* + * POSIX: + * The sem_post() interface is reentrant with respect to signals and may be + * invoked from a signal-catching function. + * The implementation does not use lock, so it should be safe. + */ +int +_libc_sem_post(sem_t *sem) +{ + if (sem_check_validity(sem) != 0) return (-1); - if ((*sem)->syssem != 0) - retval = ksem_getvalue((*sem)->semid, sval); - else { - _pthread_mutex_lock(&(*sem)->lock); - *sval = (int)(*sem)->count; - _pthread_mutex_unlock(&(*sem)->lock); - - retval = 0; - } - return (retval); + atomic_add_rel_int(&sem->_kern._count, 1); + if (sem->_kern._has_waiters) + return usem_wake(&sem->_kern); + return (0); } Index: lib/libc/gen/Makefile.inc =================================================================== --- lib/libc/gen/Makefile.inc (revision 200821) +++ lib/libc/gen/Makefile.inc (working copy) @@ -25,7 +25,7 @@ pause.c pmadvise.c popen.c posix_spawn.c \ psignal.c pw_scan.c pwcache.c \ raise.c readdir.c readpassphrase.c rewinddir.c \ - scandir.c seed48.c seekdir.c sem.c semctl.c \ + scandir.c seed48.c seekdir.c sem.c sem_compat.c semctl.c \ setdomainname.c sethostname.c setjmperr.c setmode.c \ setproctitle.c setprogname.c siginterrupt.c siglist.c signal.c \ sigsetops.c sleep.c srand48.c statvfs.c stringlist.c strtofflags.c \ Index: lib/libc/gen/_pthread_stubs.c =================================================================== --- lib/libc/gen/_pthread_stubs.c (revision 200821) +++ lib/libc/gen/_pthread_stubs.c (working copy) @@ -119,6 +119,8 @@ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_SETSPECIFIC */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_SIGMASK */ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_TESTCANCEL */ + {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CLEANUP_POP_IMP */ + {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CLEANUP_PUSH_IMP */ }; /* @@ -265,6 +267,8 @@ STUB_FUNC2(pthread_setcancelstate, PJT_SETCANCELSTATE, int, int, void *) STUB_FUNC2(pthread_setcanceltype, PJT_SETCANCELTYPE, int, int, void *) STUB_FUNC(pthread_testcancel, PJT_TESTCANCEL, void) +STUB_FUNC1(__pthread_cleanup_pop_imp, PJT_CLEANUP_POP_IMP, int, int) +STUB_FUNC2(__pthread_cleanup_push_imp, PJT_CLEANUP_PUSH_IMP, void, void*, void *); static int stub_zero(void) Index: lib/libc/gen/Symbol.map =================================================================== --- lib/libc/gen/Symbol.map (revision 200821) +++ lib/libc/gen/Symbol.map (working copy) @@ -236,16 +236,6 @@ seekdir; user_from_uid; group_from_gid; - sem_init; - sem_destroy; - sem_open; - sem_close; - sem_unlink; - sem_wait; - sem_trywait; - sem_timedwait; - sem_post; - sem_getvalue; setdomainname; sethostname; longjmperror; @@ -363,11 +353,23 @@ semctl; tcgetsid; tcsetsid; + __pthread_cleanup_pop_imp; + __pthread_cleanup_push_imp; }; FBSD_1.2 { basename_r; getpagesizes; + sem_close; + sem_destroy; + sem_getvalue; + sem_init; + sem_open; + sem_timedwait; + sem_trywait; + sem_post; + sem_wait; + sem_unlink; }; FBSDprivate_1.0 { @@ -456,16 +458,6 @@ __pw_scan; /* Used by (at least) libutil */ __raise; _raise; - __sem_init; - __sem_destroy; - __sem_open; - __sem_close; - __sem_unlink; - __sem_wait; - __sem_trywait; - __sem_timedwait; - __sem_post; - __sem_getvalue; __sleep; _sleep; _rtld_allocate_tls; @@ -482,4 +474,23 @@ _wait; __waitpid; _waitpid; + + _libc_sem_destroy; + _libc_sem_init; + _libc_sem_getvalue; + _libc_sem_trywait; + _libc_sem_wait; + _libc_sem_timedwait; + _libc_sem_post; + + _libc_sem_init_compat; + _libc_sem_destroy_compat; + _libc_sem_open_compat; + _libc_sem_close_compat; + _libc_sem_unlink_compat; + _libc_sem_wait_compat; + _libc_sem_trywait_compat; + _libc_sem_timedwait_compat; + _libc_sem_post_compat; + _libc_sem_getvalue_compat; }; Index: lib/libc/gen/sem_compat.c =================================================================== --- lib/libc/gen/sem_compat.c (revision 200821) +++ lib/libc/gen/sem_compat.c (working copy) @@ -1,5 +1,6 @@ /* * Copyright (C) 2000 Jason Evans . + * Copyright (C) 2010 David Xu . * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -59,35 +60,72 @@ #include "namespace.h" #include #include +#include #include +#include +#include +#include #include #include -#include #include #include #include -#include <_semaphore.h> #include "un-namespace.h" #include "libc_private.h" +/* + * Old semaphore definitions. + */ +struct sem { +#define SEM_MAGIC ((u_int32_t) 0x09fa4012) + u_int32_t magic; + pthread_mutex_t lock; + pthread_cond_t gtzero; + u_int32_t count; + u_int32_t nwaiters; +#define SEM_USER (NULL) + semid_t semid; /* semaphore id if kernel (shared) semaphore */ + int syssem; /* 1 if kernel (shared) semaphore */ + LIST_ENTRY(sem) entry; + struct sem **backpointer; +}; + +typedef struct sem* sem_t; + +#define SEM_FAILED ((sem_t *)0) +#define SEM_VALUE_MAX __INT_MAX + +#define SYM_FB10(sym) __CONCAT(sym, _fb10) +#define SYM_FBP10(sym) __CONCAT(sym, _fbp10) +#define WEAK_REF(sym, alias) __weak_reference(sym, alias) +#define SYM_COMPAT(sym, impl, ver) __sym_compat(sym, impl, ver) +#define SYM_DEFAULT(sym, impl, ver) __sym_default(sym, impl, ver) + +#define FB10_COMPAT(func, sym) \ + WEAK_REF(func, SYM_FB10(sym)); \ + SYM_COMPAT(sym, SYM_FB10(sym), FBSD_1.0) + +#define FB10_COMPAT_PRIVATE(func, sym) \ + WEAK_REF(func, SYM_FBP10(sym)); \ + SYM_DEFAULT(sym, SYM_FBP10(sym), FBSDprivate_1.0) + static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); static void sem_free(sem_t sem); static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(&named_sems); static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER; -__weak_reference(__sem_init, sem_init); -__weak_reference(__sem_destroy, sem_destroy); -__weak_reference(__sem_open, sem_open); -__weak_reference(__sem_close, sem_close); -__weak_reference(__sem_unlink, sem_unlink); -__weak_reference(__sem_wait, sem_wait); -__weak_reference(__sem_trywait, sem_trywait); -__weak_reference(__sem_timedwait, sem_timedwait); -__weak_reference(__sem_post, sem_post); -__weak_reference(__sem_getvalue, sem_getvalue); +FB10_COMPAT(_libc_sem_init_compat, sem_init); +FB10_COMPAT(_libc_sem_destroy_compat, sem_destroy); +FB10_COMPAT(_libc_sem_open_compat, sem_open); +FB10_COMPAT(_libc_sem_close_compat, sem_close); +FB10_COMPAT(_libc_sem_unlink_compat, sem_unlink); +FB10_COMPAT(_libc_sem_wait_compat, sem_wait); +FB10_COMPAT(_libc_sem_trywait_compat, sem_trywait); +FB10_COMPAT(_libc_sem_timedwait_compat, sem_timedwait); +FB10_COMPAT(_libc_sem_post_compat, sem_post); +FB10_COMPAT(_libc_sem_getvalue_compat, sem_getvalue); - static inline int sem_check_validity(sem_t *sem) { @@ -104,8 +142,6 @@ sem_free(sem_t sem) { - _pthread_mutex_destroy(&sem->lock); - _pthread_cond_destroy(&sem->gtzero); sem->magic = 0; free(sem); } @@ -131,13 +167,11 @@ sem->magic = SEM_MAGIC; sem->semid = semid; sem->syssem = system_sem; - sem->lock = PTHREAD_MUTEX_INITIALIZER; - sem->gtzero = PTHREAD_COND_INITIALIZER; return (sem); } int -__sem_init(sem_t *sem, int pshared, unsigned int value) +_libc_sem_init_compat(sem_t *sem, int pshared, unsigned int value) { semid_t semid; @@ -147,26 +181,27 @@ * pthread_cond_wait() is just a stub that doesn't really * wait. */ - if (ksem_init(&semid, value) != 0) + semid = (semid_t)SEM_USER; + if ((pshared != 0) && ksem_init(&semid, value) != 0) return (-1); - (*sem) = sem_alloc(value, semid, 1); + *sem = sem_alloc(value, semid, pshared); if ((*sem) == NULL) { - ksem_destroy(semid); + if (pshared != 0) + ksem_destroy(semid); return (-1); } return (0); } int -__sem_destroy(sem_t *sem) +_libc_sem_destroy_compat(sem_t *sem) { int retval; if (sem_check_validity(sem) != 0) return (-1); - _pthread_mutex_lock(&(*sem)->lock); /* * If this is a system semaphore let the kernel track it otherwise * make sure there are no waiters. @@ -181,18 +216,14 @@ retval = 0; (*sem)->magic = 0; } - _pthread_mutex_unlock(&(*sem)->lock); - if (retval == 0) { - _pthread_mutex_destroy(&(*sem)->lock); - _pthread_cond_destroy(&(*sem)->gtzero); + if (retval == 0) sem_free(*sem); - } return (retval); } sem_t * -__sem_open(const char *name, int oflag, ...) +_libc_sem_open_compat(const char *name, int oflag, ...) { sem_t *sem; sem_t s; @@ -255,7 +286,7 @@ } int -__sem_close(sem_t *sem) +_libc_sem_close_compat(sem_t *sem) { if (sem_check_validity(sem) != 0) @@ -280,68 +311,153 @@ } int -__sem_unlink(const char *name) +_libc_sem_unlink_compat(const char *name) { return (ksem_unlink(name)); } -int -__sem_wait(sem_t *sem) +static int +enable_async_cancel(void) { + int old; - if (sem_check_validity(sem) != 0) + _pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old); + return (old); +} + +static void +restore_async_cancel(int val) +{ + _pthread_setcanceltype(val, NULL); +} + +static int +_umtx_wait_uint(volatile unsigned *mtx, unsigned id, const struct timespec *timeout) +{ + if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 && + timeout->tv_nsec <= 0))) { + errno = ETIMEDOUT; return (-1); + } + return _umtx_op(__DEVOLATILE(void *, mtx), + UMTX_OP_WAIT_UINT_PRIVATE, id, 0, __DECONST(void*, timeout)); +} - return (ksem_wait((*sem)->semid)); +#define TIMESPEC_SUB(dst, src, val) \ + do { \ + (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \ + (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \ + if ((dst)->tv_nsec < 0) { \ + (dst)->tv_sec--; \ + (dst)->tv_nsec += 1000000000; \ + } \ + } while (0) + + +static int +_umtx_wake(volatile void *mtx) +{ + return _umtx_op(__DEVOLATILE(void *, mtx), + UMTX_OP_WAKE_PRIVATE, 1, 0, 0); } +static void +sem_cancel_handler(void *arg) +{ + sem_t *sem = arg; + + atomic_add_int(&(*sem)->nwaiters, -1); + if ((*sem)->nwaiters && (*sem)->count) + _umtx_wake(&(*sem)->count); +} + int -__sem_trywait(sem_t *sem) +_libc_sem_timedwait_compat(sem_t * __restrict sem, + const struct timespec * __restrict abstime) { - int retval; + struct timespec ts, ts2; + int val, retval, saved_cancel; if (sem_check_validity(sem) != 0) return (-1); - if ((*sem)->syssem != 0) - retval = ksem_trywait((*sem)->semid); - else { - _pthread_mutex_lock(&(*sem)->lock); - if ((*sem)->count > 0) { - (*sem)->count--; - retval = 0; - } else { - errno = EAGAIN; - retval = -1; + if ((*sem)->syssem != 0) { + saved_cancel = enable_async_cancel(); + retval = ksem_wait((*sem)->semid); + restore_async_cancel(saved_cancel); + return (retval); + } + + _pthread_testcancel(); + do { + while ((val = (*sem)->count) > 0) { + if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) + return (0); } - _pthread_mutex_unlock(&(*sem)->lock); - } - return (retval); + if (abstime) { + if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) { + errno = EINVAL; + return (-1); + } + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + } + atomic_add_int(&(*sem)->nwaiters, 1); + pthread_cleanup_push(sem_cancel_handler, sem); + saved_cancel = enable_async_cancel(); + retval = _umtx_wait_uint(&(*sem)->count, 0, abstime ? &ts2 : NULL); + restore_async_cancel(saved_cancel); + pthread_cleanup_pop(0); + atomic_add_int(&(*sem)->nwaiters, -1); + } while (retval == 0); + return (-1); } int -__sem_timedwait(sem_t * __restrict sem, - const struct timespec * __restrict abs_timeout) +_libc_sem_wait_compat(sem_t *sem) { + return _libc_sem_timedwait_compat(sem, NULL); +} + +int +_libc_sem_trywait_compat(sem_t *sem) +{ + int val; + if (sem_check_validity(sem) != 0) return (-1); - return (ksem_timedwait((*sem)->semid, abs_timeout)); + if ((*sem)->syssem != 0) + return ksem_trywait((*sem)->semid); + + while ((val = (*sem)->count) > 0) { + if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) + return (0); + } + errno = EAGAIN; + return (-1); } int -__sem_post(sem_t *sem) +_libc_sem_post_compat(sem_t *sem) { if (sem_check_validity(sem) != 0) return (-1); - return (ksem_post((*sem)->semid)); + if ((*sem)->syssem != 0) + return ksem_post((*sem)->semid); + + atomic_add_rel_int(&(*sem)->count, 1); + + if ((*sem)->nwaiters) + return _umtx_wake(&(*sem)->count); + return (0); } int -__sem_getvalue(sem_t * __restrict sem, int * __restrict sval) +_libc_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval) { int retval; @@ -351,10 +467,7 @@ if ((*sem)->syssem != 0) retval = ksem_getvalue((*sem)->semid, sval); else { - _pthread_mutex_lock(&(*sem)->lock); *sval = (int)(*sem)->count; - _pthread_mutex_unlock(&(*sem)->lock); - retval = 0; } return (retval); Property changes on: lib/libc/gen/sem_compat.c ___________________________________________________________________ Added: svn:mergeinfo Merged /user/netchild/misc/src/lib/libc/gen/sem.c:r183949 Index: lib/libc/include/libc_private.h =================================================================== --- lib/libc/include/libc_private.h (revision 200821) +++ lib/libc/include/libc_private.h (working copy) @@ -127,6 +127,8 @@ PJT_SETSPECIFIC, PJT_SIGMASK, PJT_TESTCANCEL, + PJT_CLEANUP_POP_IMP, + PJT_CLEANUP_PUSH_IMP, PJT_MAX } pjt_index_t; Index: lib/libthr/pthread.map =================================================================== --- lib/libthr/pthread.map (revision 200821) +++ lib/libthr/pthread.map (working copy) @@ -145,13 +145,6 @@ recvfrom; recvmsg; select; - sem_destroy; - sem_getvalue; - sem_init; - sem_post; - sem_timedwait; - sem_trywait; - sem_wait; sendmsg; sendto; sigaction; @@ -348,13 +341,6 @@ _pthread_timedjoin_np; _pthread_yield; _raise; - _sem_destroy; - _sem_getvalue; - _sem_init; - _sem_post; - _sem_timedwait; - _sem_trywait; - _sem_wait; _sigaction; _sigprocmask; _sigsuspend; @@ -410,4 +396,11 @@ FBSD_1.2 { openat; + sem_destroy; + sem_getvalue; + sem_init; + sem_post; + sem_timedwait; + sem_trywait; + sem_wait; }; Index: lib/libthr/thread/thr_sem.c =================================================================== --- lib/libthr/thread/thr_sem.c (revision 200827) +++ lib/libthr/thread/thr_sem.c (working copy) @@ -27,7 +27,7 @@ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD$ + * $FreeBSD: head/lib/libthr/thread/thr_sem.c 178647 2008-04-29 03:58:18Z davidxu $ */ #include "namespace.h" @@ -36,15 +36,13 @@ #include #include #include -#include #include #include -#include <_semaphore.h> +#include #include "un-namespace.h" #include "thr_private.h" - __weak_reference(_sem_init, sem_init); __weak_reference(_sem_destroy, sem_destroy); __weak_reference(_sem_getvalue, sem_getvalue); @@ -53,239 +51,54 @@ __weak_reference(_sem_timedwait, sem_timedwait); __weak_reference(_sem_post, sem_post); +extern int _libc_sem_init(sem_t *sem, int pshared, unsigned int value); +extern int _libc_sem_destroy(sem_t *sem); +extern int _libc_sem_getvalue(sem_t * __restrict sem, int * __restrict sval); +extern int _libc_sem_trywait(sem_t *sem); +extern int _libc_sem_wait(sem_t *sem); +extern int _libc_sem_timedwait(sem_t * __restrict sem, + const struct timespec * __restrict abstime); +extern int _libc_sem_post(sem_t *sem); -static inline int -sem_check_validity(sem_t *sem) -{ - - if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC)) - return (0); - else { - errno = EINVAL; - return (-1); - } -} - -static sem_t -sem_alloc(unsigned int value, semid_t semid, int system_sem) -{ - sem_t sem; - - if (value > SEM_VALUE_MAX) { - errno = EINVAL; - return (NULL); - } - - sem = (sem_t)malloc(sizeof(struct sem)); - if (sem == NULL) { - errno = ENOSPC; - return (NULL); - } - bzero(sem, sizeof(*sem)); - /* - * Fortunatly count and nwaiters are adjacency, so we can - * use umtx_wait to wait on it, umtx_wait needs an address - * can be accessed as a long interger. - */ - sem->count = (u_int32_t)value; - sem->nwaiters = 0; - sem->magic = SEM_MAGIC; - sem->semid = semid; - sem->syssem = system_sem; - return (sem); -} - int _sem_init(sem_t *sem, int pshared, unsigned int value) { - semid_t semid; - - semid = (semid_t)SEM_USER; - if ((pshared != 0) && (ksem_init(&semid, value) != 0)) - return (-1); - - (*sem) = sem_alloc(value, semid, pshared); - if ((*sem) == NULL) { - if (pshared != 0) - ksem_destroy(semid); - return (-1); - } - return (0); + return _libc_sem_init(sem, pshared, value); } int _sem_destroy(sem_t *sem) { - int retval; - - if (sem_check_validity(sem) != 0) - return (-1); - - /* - * If this is a system semaphore let the kernel track it otherwise - * make sure there are no waiters. - */ - if ((*sem)->syssem != 0) - retval = ksem_destroy((*sem)->semid); - else { - retval = 0; - (*sem)->magic = 0; - } - if (retval == 0) - free(*sem); - return (retval); + return _libc_sem_destroy(sem); } int _sem_getvalue(sem_t * __restrict sem, int * __restrict sval) { - int retval; - - if (sem_check_validity(sem) != 0) - return (-1); - - if ((*sem)->syssem != 0) - retval = ksem_getvalue((*sem)->semid, sval); - else { - *sval = (int)(*sem)->count; - retval = 0; - } - return (retval); + return _libc_sem_getvalue(sem, sval); } int _sem_trywait(sem_t *sem) { - int val; - - if (sem_check_validity(sem) != 0) - return (-1); - - if ((*sem)->syssem != 0) - return (ksem_trywait((*sem)->semid)); - - while ((val = (*sem)->count) > 0) { - if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) - return (0); - } - errno = EAGAIN; - return (-1); + return _libc_sem_trywait(sem); } -static void -sem_cancel_handler(void *arg) -{ - sem_t *sem = arg; - - atomic_add_int(&(*sem)->nwaiters, -1); - if ((*sem)->nwaiters && (*sem)->count) - _thr_umtx_wake(&(*sem)->count, 1, 0); -} - int _sem_wait(sem_t *sem) { - struct pthread *curthread; - int val, retval; - - if (sem_check_validity(sem) != 0) - return (-1); - - curthread = _get_curthread(); - if ((*sem)->syssem != 0) { - _thr_cancel_enter(curthread); - retval = ksem_wait((*sem)->semid); - _thr_cancel_leave(curthread); - return (retval); - } - - _pthread_testcancel(); - do { - while ((val = (*sem)->count) > 0) { - if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) - return (0); - } - atomic_add_int(&(*sem)->nwaiters, 1); - THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem); - _thr_cancel_enter(curthread); - retval = _thr_umtx_wait_uint(&(*sem)->count, 0, NULL, 0); - _thr_cancel_leave(curthread); - THR_CLEANUP_POP(curthread, 0); - atomic_add_int(&(*sem)->nwaiters, -1); - } while (retval == 0); - errno = retval; - return (-1); + return _libc_sem_wait(sem); } int _sem_timedwait(sem_t * __restrict sem, const struct timespec * __restrict abstime) { - struct timespec ts, ts2; - struct pthread *curthread; - int val, retval; - - if (sem_check_validity(sem) != 0) - return (-1); - - curthread = _get_curthread(); - if ((*sem)->syssem != 0) { - _thr_cancel_enter(curthread); - retval = ksem_timedwait((*sem)->semid, abstime); - _thr_cancel_leave(curthread); - return (retval); - } - - /* - * The timeout argument is only supposed to - * be checked if the thread would have blocked. - */ - _pthread_testcancel(); - do { - while ((val = (*sem)->count) > 0) { - if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) - return (0); - } - if (abstime == NULL) { - errno = EINVAL; - return (-1); - } - clock_gettime(CLOCK_REALTIME, &ts); - TIMESPEC_SUB(&ts2, abstime, &ts); - atomic_add_int(&(*sem)->nwaiters, 1); - THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem); - _thr_cancel_enter(curthread); - retval = _thr_umtx_wait_uint((uint32_t*)&(*sem)->count, 0, &ts2, 0); - _thr_cancel_leave(curthread); - THR_CLEANUP_POP(curthread, 0); - atomic_add_int(&(*sem)->nwaiters, -1); - } while (retval == 0); - errno = retval; - return (-1); + return _libc_sem_timedwait(sem, abstime); } -/* - * sem_post() is required to be safe to call from within - * signal handlers, these code should work as that. - */ - int _sem_post(sem_t *sem) { - int retval = 0; - - if (sem_check_validity(sem) != 0) - return (-1); - - if ((*sem)->syssem != 0) - return (ksem_post((*sem)->semid)); - - atomic_add_rel_int(&(*sem)->count, 1); - - if ((*sem)->nwaiters) { - retval = _thr_umtx_wake(&(*sem)->count, 1, 0); - if (retval != 0) - retval = -1; - } - return (retval); + return _libc_sem_post(sem); } Index: lib/libthr/thread/Makefile.inc =================================================================== --- lib/libthr/thread/Makefile.inc (revision 200821) +++ lib/libthr/thread/Makefile.inc (working copy) @@ -41,6 +41,7 @@ thr_rwlockattr.c \ thr_self.c \ thr_sem.c \ + thr_sem_compat.c \ thr_setprio.c \ thr_setschedparam.c \ thr_sig.c \ Index: lib/libthr/thread/thr_sem_compat.c =================================================================== --- lib/libthr/thread/thr_sem_compat.c (revision 200821) +++ lib/libthr/thread/thr_sem_compat.c (working copy) @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include <_semaphore.h> @@ -44,248 +43,71 @@ #include "thr_private.h" +FB10_COMPAT(_sem_init_compat, sem_init); +FB10_COMPAT(_sem_destroy_compat, sem_destroy); +FB10_COMPAT(_sem_getvalue_compat, sem_getvalue); +FB10_COMPAT(_sem_trywait_compat, sem_trywait); +FB10_COMPAT(_sem_wait_compat, sem_wait); +FB10_COMPAT(_sem_timedwait_compat, sem_timedwait); +FB10_COMPAT(_sem_post_compat, sem_post); -__weak_reference(_sem_init, sem_init); -__weak_reference(_sem_destroy, sem_destroy); -__weak_reference(_sem_getvalue, sem_getvalue); -__weak_reference(_sem_trywait, sem_trywait); -__weak_reference(_sem_wait, sem_wait); -__weak_reference(_sem_timedwait, sem_timedwait); -__weak_reference(_sem_post, sem_post); +extern int _libc_sem_init_compat(sem_t *sem, int pshared, unsigned int value); +extern int _libc_sem_destroy_compat(sem_t *sem); +extern int _libc_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval); +extern int _libc_sem_trywait_compat(sem_t *sem); +extern int _libc_sem_wait_compat(sem_t *sem); +extern int _libc_sem_timedwait_compat(sem_t * __restrict sem, + const struct timespec * __restrict abstime); +extern int _libc_sem_post_compat(sem_t *sem); +int _sem_init_compat(sem_t *sem, int pshared, unsigned int value); +int _sem_destroy_compat(sem_t *sem); +int _sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval); +int _sem_trywait_compat(sem_t *sem); +int _sem_wait_compat(sem_t *sem); +int _sem_timedwait_compat(sem_t * __restrict sem, + const struct timespec * __restrict abstime); +int _sem_post_compat(sem_t *sem); -static inline int -sem_check_validity(sem_t *sem) -{ - - if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC)) - return (0); - else { - errno = EINVAL; - return (-1); - } -} - -static sem_t -sem_alloc(unsigned int value, semid_t semid, int system_sem) -{ - sem_t sem; - - if (value > SEM_VALUE_MAX) { - errno = EINVAL; - return (NULL); - } - - sem = (sem_t)malloc(sizeof(struct sem)); - if (sem == NULL) { - errno = ENOSPC; - return (NULL); - } - bzero(sem, sizeof(*sem)); - /* - * Fortunatly count and nwaiters are adjacency, so we can - * use umtx_wait to wait on it, umtx_wait needs an address - * can be accessed as a long interger. - */ - sem->count = (u_int32_t)value; - sem->nwaiters = 0; - sem->magic = SEM_MAGIC; - sem->semid = semid; - sem->syssem = system_sem; - return (sem); -} - int -_sem_init(sem_t *sem, int pshared, unsigned int value) +_sem_init_compat(sem_t *sem, int pshared, unsigned int value) { - semid_t semid; - - semid = (semid_t)SEM_USER; - if ((pshared != 0) && (ksem_init(&semid, value) != 0)) - return (-1); - - (*sem) = sem_alloc(value, semid, pshared); - if ((*sem) == NULL) { - if (pshared != 0) - ksem_destroy(semid); - return (-1); - } - return (0); + return _libc_sem_init_compat(sem, pshared, value); } int -_sem_destroy(sem_t *sem) +_sem_destroy_compat(sem_t *sem) { - int retval; - - if (sem_check_validity(sem) != 0) - return (-1); - - /* - * If this is a system semaphore let the kernel track it otherwise - * make sure there are no waiters. - */ - if ((*sem)->syssem != 0) - retval = ksem_destroy((*sem)->semid); - else { - retval = 0; - (*sem)->magic = 0; - } - if (retval == 0) - free(*sem); - return (retval); + return _libc_sem_destroy_compat(sem); } int -_sem_getvalue(sem_t * __restrict sem, int * __restrict sval) +_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval) { - int retval; - - if (sem_check_validity(sem) != 0) - return (-1); - - if ((*sem)->syssem != 0) - retval = ksem_getvalue((*sem)->semid, sval); - else { - *sval = (int)(*sem)->count; - retval = 0; - } - return (retval); + return _libc_sem_getvalue_compat(sem, sval); } int -_sem_trywait(sem_t *sem) +_sem_trywait_compat(sem_t *sem) { - int val; - - if (sem_check_validity(sem) != 0) - return (-1); - - if ((*sem)->syssem != 0) - return (ksem_trywait((*sem)->semid)); - - while ((val = (*sem)->count) > 0) { - if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) - return (0); - } - errno = EAGAIN; - return (-1); + return _libc_sem_trywait_compat(sem); } -static void -sem_cancel_handler(void *arg) -{ - sem_t *sem = arg; - - atomic_add_int(&(*sem)->nwaiters, -1); - if ((*sem)->nwaiters && (*sem)->count) - _thr_umtx_wake(&(*sem)->count, 1, 0); -} - int -_sem_wait(sem_t *sem) +_sem_wait_compat(sem_t *sem) { - struct pthread *curthread; - int val, retval; - - if (sem_check_validity(sem) != 0) - return (-1); - - curthread = _get_curthread(); - if ((*sem)->syssem != 0) { - _thr_cancel_enter(curthread); - retval = ksem_wait((*sem)->semid); - _thr_cancel_leave(curthread); - return (retval); - } - - _pthread_testcancel(); - do { - while ((val = (*sem)->count) > 0) { - if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) - return (0); - } - atomic_add_int(&(*sem)->nwaiters, 1); - THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem); - _thr_cancel_enter(curthread); - retval = _thr_umtx_wait_uint(&(*sem)->count, 0, NULL, 0); - _thr_cancel_leave(curthread); - THR_CLEANUP_POP(curthread, 0); - atomic_add_int(&(*sem)->nwaiters, -1); - } while (retval == 0); - errno = retval; - return (-1); + return _libc_sem_wait_compat(sem); } int -_sem_timedwait(sem_t * __restrict sem, +_sem_timedwait_compat(sem_t * __restrict sem, const struct timespec * __restrict abstime) { - struct timespec ts, ts2; - struct pthread *curthread; - int val, retval; - - if (sem_check_validity(sem) != 0) - return (-1); - - curthread = _get_curthread(); - if ((*sem)->syssem != 0) { - _thr_cancel_enter(curthread); - retval = ksem_timedwait((*sem)->semid, abstime); - _thr_cancel_leave(curthread); - return (retval); - } - - /* - * The timeout argument is only supposed to - * be checked if the thread would have blocked. - */ - _pthread_testcancel(); - do { - while ((val = (*sem)->count) > 0) { - if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) - return (0); - } - if (abstime == NULL) { - errno = EINVAL; - return (-1); - } - clock_gettime(CLOCK_REALTIME, &ts); - TIMESPEC_SUB(&ts2, abstime, &ts); - atomic_add_int(&(*sem)->nwaiters, 1); - THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem); - _thr_cancel_enter(curthread); - retval = _thr_umtx_wait_uint((uint32_t*)&(*sem)->count, 0, &ts2, 0); - _thr_cancel_leave(curthread); - THR_CLEANUP_POP(curthread, 0); - atomic_add_int(&(*sem)->nwaiters, -1); - } while (retval == 0); - errno = retval; - return (-1); + return _libc_sem_timedwait_compat(sem, abstime); } -/* - * sem_post() is required to be safe to call from within - * signal handlers, these code should work as that. - */ - int -_sem_post(sem_t *sem) +_sem_post_compat(sem_t *sem) { - int retval = 0; - - if (sem_check_validity(sem) != 0) - return (-1); - - if ((*sem)->syssem != 0) - return (ksem_post((*sem)->semid)); - - atomic_add_rel_int(&(*sem)->count, 1); - - if ((*sem)->nwaiters) { - retval = _thr_umtx_wake(&(*sem)->count, 1, 0); - if (retval != 0) - retval = -1; - } - return (retval); + return _libc_sem_post_compat(sem); } Property changes on: lib/libthr/thread/thr_sem_compat.c ___________________________________________________________________ Added: svn:mergeinfo Index: lib/libthr/thread/thr_private.h =================================================================== --- lib/libthr/thread/thr_private.h (revision 200821) +++ lib/libthr/thread/thr_private.h (working copy) @@ -52,6 +52,20 @@ #include #include +#define SYM_FB10(sym) __CONCAT(sym, _fb10) +#define SYM_FBP10(sym) __CONCAT(sym, _fbp10) +#define WEAK_REF(sym, alias) __weak_reference(sym, alias) +#define SYM_COMPAT(sym, impl, ver) __sym_compat(sym, impl, ver) +#define SYM_DEFAULT(sym, impl, ver) __sym_default(sym, impl, ver) + +#define FB10_COMPAT(func, sym) \ + WEAK_REF(func, SYM_FB10(sym)); \ + SYM_COMPAT(sym, SYM_FB10(sym), FBSD_1.0) + +#define FB10_COMPAT_PRIVATE(func, sym) \ + WEAK_REF(func, SYM_FBP10(sym)); \ + SYM_DEFAULT(sym, SYM_FBP10(sym), FBSDprivate_1.0) + #ifndef __hidden #define __hidden __attribute__((visibility("hidden"))) #endif @@ -660,6 +674,9 @@ void _thread_bp_create(void); void _thread_bp_death(void); int _sched_yield(void); +void _thr_sem_prefork(void); +void _thr_sem_postfork(void); +void _thr_sem_child_postfork(void); void _pthread_cleanup_push(void (*)(void *), void *); void _pthread_cleanup_pop(int); Index: lib/libthr/thread/thr_umtx.c =================================================================== --- lib/libthr/thread/thr_umtx.c (revision 200821) +++ lib/libthr/thread/thr_umtx.c (working copy) @@ -201,6 +201,24 @@ } int +_thr_usem_wait(struct _usem *sem, const struct timespec *timeout) +{ + if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 && + timeout->tv_nsec <= 0))) + return (ETIMEDOUT); + return _umtx_op_err(sem, UMTX_OP_SEM_WAIT, 0, NULL, + __DECONST(void*, timeout)); +} + +int +_thr_usem_wake(struct _usem *sem) +{ + if (!sem->s_has_waiters) + return (0); + return _umtx_op_err(sem, UMTX_OP_SEM_WAKE, 0, NULL, NULL); +} + +int __thr_rwlock_rdlock(struct urwlock *rwlock, int flags, struct timespec *tsp) { return _umtx_op_err(rwlock, UMTX_OP_RW_RDLOCK, flags, NULL, tsp); Index: lib/libthr/thread/thr_umtx.h =================================================================== --- lib/libthr/thread/thr_umtx.h (revision 200821) +++ lib/libthr/thread/thr_umtx.h (working copy) @@ -58,6 +58,9 @@ int __thr_rwlock_wrlock(struct urwlock *rwlock, struct timespec *tsp) __hidden; int __thr_rwlock_unlock(struct urwlock *rwlock) __hidden; +int _thr_usem_wait(struct _usem *sem, const struct timespec *timeout) __hidden; +int _thr_usem_wake(struct _usem *sem) __hidden; + static inline int _thr_umutex_trylock(struct umutex *mtx, uint32_t id) { Index: lib/libthr/thread/thr_init.c =================================================================== --- lib/libthr/thread/thr_init.c (revision 200821) +++ lib/libthr/thread/thr_init.c (working copy) @@ -246,7 +246,9 @@ {DUAL_ENTRY(_pthread_setcanceltype)}, /* PJT_SETCANCELTYPE */ {DUAL_ENTRY(_pthread_setspecific)}, /* PJT_SETSPECIFIC */ {DUAL_ENTRY(_pthread_sigmask)}, /* PJT_SIGMASK */ - {DUAL_ENTRY(_pthread_testcancel)} /* PJT_TESTCANCEL */ + {DUAL_ENTRY(_pthread_testcancel)}, /* PJT_TESTCANCEL */ + {DUAL_ENTRY(__pthread_cleanup_pop_imp)},/* PJT_CLEANUP_POP_IMP */ + {DUAL_ENTRY(__pthread_cleanup_push_imp)}/* PJT_CLEANUP_PUSH_IMP */ }; static int init_once = 0; Index: sys/sys/_semaphore.h =================================================================== --- sys/sys/_semaphore.h (revision 200821) +++ sys/sys/_semaphore.h (working copy) @@ -31,27 +31,10 @@ typedef intptr_t semid_t; struct timespec; +#define SEM_VALUE_MAX __INT_MAX + #ifndef _KERNEL -#include - -/* - * Semaphore definitions. - */ -struct sem { -#define SEM_MAGIC ((u_int32_t) 0x09fa4012) - u_int32_t magic; - pthread_mutex_t lock; - pthread_cond_t gtzero; - u_int32_t count; - u_int32_t nwaiters; -#define SEM_USER (NULL) - semid_t semid; /* semaphore id if kernel (shared) semaphore */ - int syssem; /* 1 if kernel (shared) semaphore */ - LIST_ENTRY(sem) entry; - struct sem **backpointer; -}; - __BEGIN_DECLS int ksem_close(semid_t id); Index: sys/sys/_umtx.h =================================================================== --- sys/sys/_umtx.h (revision 0) +++ sys/sys/_umtx.h (revision 0) @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2010, David Xu + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#ifndef _SYS__UMTX_H_ +#define _SYS__UMTX_H_ + +#include + +struct umtx { + volatile unsigned long u_owner; /* Owner of the mutex. */ +}; + +struct umutex { + volatile __lwpid_t m_owner; /* Owner of the mutex */ + __uint32_t m_flags; /* Flags of the mutex */ + __uint32_t m_ceilings[2]; /* Priority protect ceiling */ + __uint32_t m_spare[4]; +}; + +struct ucond { + volatile __uint32_t c_has_waiters; /* Has waiters in kernel */ + __uint32_t c_flags; /* Flags of the condition variable */ + __uint32_t c_spare[2]; /* Spare space */ +}; + +struct urwlock { + volatile __int32_t rw_state; + __uint32_t rw_flags; + __uint32_t rw_blocked_readers; + __uint32_t rw_blocked_writers; + __uint32_t rw_spare[4]; +}; + +struct _usem { + volatile __uint32_t _has_waiters; + volatile __uint32_t _count; + __uint32_t _flags; +}; + +#endif /* !_SYS__UMTX_H_ */ Index: sys/sys/umtx.h =================================================================== --- sys/sys/umtx.h (revision 200821) +++ sys/sys/umtx.h (working copy) @@ -30,20 +30,12 @@ #ifndef _SYS_UMTX_H_ #define _SYS_UMTX_H_ -#include +#include #include -/* - * See pthread_* - */ +#define UMTX_UNOWNED 0x0 +#define UMTX_CONTESTED LONG_MIN -#define UMTX_UNOWNED 0x0 -#define UMTX_CONTESTED LONG_MIN - -struct umtx { - volatile u_long u_owner; /* Owner of the mutex. */ -}; - #define USYNC_PROCESS_SHARED 0x0001 /* Process shared sync objs */ #define UMUTEX_UNOWNED 0x0 @@ -53,27 +45,6 @@ #define UMUTEX_PRIO_INHERIT 0x0004 /* Priority inherited mutex */ #define UMUTEX_PRIO_PROTECT 0x0008 /* Priority protect mutex */ -struct umutex { - volatile __lwpid_t m_owner; /* Owner of the mutex */ - uint32_t m_flags; /* Flags of the mutex */ - uint32_t m_ceilings[2]; /* Priority protect ceiling */ - uint32_t m_spare[4]; -}; - -struct ucond { - volatile uint32_t c_has_waiters; /* Has waiters in kernel */ - uint32_t c_flags; /* Flags of the condition variable */ - uint32_t c_spare[2]; /* Spare space */ -}; - -struct urwlock { - volatile int32_t rw_state; - uint32_t rw_flags; - uint32_t rw_blocked_readers; - uint32_t rw_blocked_writers; - uint32_t rw_spare[4]; -}; - /* urwlock flags */ #define URWLOCK_PREFER_READER 0x0002 @@ -83,6 +54,9 @@ #define URWLOCK_MAX_READERS 0x1fffffffU #define URWLOCK_READER_COUNT(c) ((c) & URWLOCK_MAX_READERS) +/* _usem flags */ +#define SEM_NAMED 0x0002 + /* op code for _umtx_op */ #define UMTX_OP_LOCK 0 #define UMTX_OP_UNLOCK 1 @@ -100,10 +74,12 @@ #define UMTX_OP_RW_WRLOCK 13 #define UMTX_OP_RW_UNLOCK 14 #define UMTX_OP_WAIT_UINT_PRIVATE 15 -#define UMTX_OP_WAKE_PRIVATE 16 -#define UMTX_OP_MUTEX_WAIT 17 -#define UMTX_OP_MUTEX_WAKE 18 -#define UMTX_OP_MAX 19 +#define UMTX_OP_WAKE_PRIVATE 16 +#define UMTX_OP_MUTEX_WAIT 17 +#define UMTX_OP_MUTEX_WAKE 18 +#define UMTX_OP_SEM_WAIT 19 +#define UMTX_OP_SEM_WAKE 20 +#define UMTX_OP_MAX 21 /* flags for UMTX_OP_CV_WAIT */ #define UMTX_CHECK_UNPARKING 0x01 Index: sys/sys/semaphore.h =================================================================== --- sys/sys/semaphore.h (revision 200821) +++ sys/sys/semaphore.h (working copy) @@ -1,69 +0,0 @@ -/*- - * Copyright (c) 1996, 1997 - * HD Associates, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by HD Associates, Inc - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* semaphore.h: POSIX 1003.1b semaphores */ - -#ifndef _SEMAPHORE_H_ -#define _SEMAPHORE_H_ - -#include - -/* Opaque type definition. */ -struct sem; -typedef struct sem * sem_t; - -#define SEM_FAILED ((sem_t *)0) -#define SEM_VALUE_MAX __INT_MAX - -#ifndef _KERNEL -#include - -struct timespec; - -__BEGIN_DECLS -int sem_close(sem_t *); -int sem_destroy(sem_t *); -int sem_getvalue(sem_t * __restrict, int * __restrict); -int sem_init(sem_t *, int, unsigned int); -sem_t *sem_open(const char *, int, ...); -int sem_post(sem_t *); -int sem_timedwait(sem_t * __restrict, const struct timespec * __restrict); -int sem_trywait(sem_t *); -int sem_unlink(const char *); -int sem_wait(sem_t *); -__END_DECLS - -#endif - -#endif /* !_SEMAPHORE_H_ */ Index: sys/kern/kern_umtx.c =================================================================== --- sys/kern/kern_umtx.c (revision 200821) +++ sys/kern/kern_umtx.c (working copy) @@ -2759,6 +2759,110 @@ return (error); } +static int +do_sem_wait(struct thread *td, struct _usem *sem, struct timespec *timeout) +{ + struct umtx_q *uq; + struct timeval tv; + struct timespec cts, ets, tts; + uint32_t flags, count; + int error; + + uq = td->td_umtxq; + flags = fuword32(&sem->_flags); + error = umtx_key_get(sem, TYPE_CV, GET_SHARE(flags), &uq->uq_key); + if (error != 0) + return (error); + umtxq_lock(&uq->uq_key); + umtxq_busy(&uq->uq_key); + umtxq_insert(uq); + umtxq_unlock(&uq->uq_key); + + count = fuword32(__DEVOLATILE(uint32_t *, &sem->_count)); + if (count != 0) { + umtxq_lock(&uq->uq_key); + umtxq_unbusy(&uq->uq_key); + umtxq_remove(uq); + umtxq_unlock(&uq->uq_key); + umtx_key_release(&uq->uq_key); + return (0); + } + + /* + * The magic thing is we should set c_has_waiters to 1 before + * releasing user mutex. + */ + suword32(__DEVOLATILE(uint32_t *, &sem->_has_waiters), 1); + + umtxq_lock(&uq->uq_key); + umtxq_unbusy(&uq->uq_key); + umtxq_unlock(&uq->uq_key); + + umtxq_lock(&uq->uq_key); + if (timeout == NULL) { + error = umtxq_sleep(uq, "usem", 0); + } else { + getnanouptime(&ets); + timespecadd(&ets, timeout); + TIMESPEC_TO_TIMEVAL(&tv, timeout); + for (;;) { + error = umtxq_sleep(uq, "usem", tvtohz(&tv)); + if (error != ETIMEDOUT) + break; + getnanouptime(&cts); + if (timespeccmp(&cts, &ets, >=)) { + error = ETIMEDOUT; + break; + } + tts = ets; + timespecsub(&tts, &cts); + TIMESPEC_TO_TIMEVAL(&tv, &tts); + } + } + + if (error != 0) { + if ((uq->uq_flags & UQF_UMTXQ) == 0) { + if (!umtxq_signal(&uq->uq_key, 1)) + error = 0; + } + if (error == ERESTART) + error = EINTR; + } + umtxq_remove(uq); + umtxq_unlock(&uq->uq_key); + umtx_key_release(&uq->uq_key); + return (error); +} + +/* + * Signal a userland condition variable. + */ +static int +do_sem_wake(struct thread *td, struct _usem *sem) +{ + struct umtx_key key; + int error, cnt, nwake; + uint32_t flags; + + flags = fuword32(&sem->_flags); + if ((error = umtx_key_get(sem, TYPE_CV, GET_SHARE(flags), &key)) != 0) + return (error); + umtxq_lock(&key); + umtxq_busy(&key); + cnt = umtxq_count(&key); + nwake = umtxq_signal(&key, 1); + if (cnt <= nwake) { + umtxq_unlock(&key); + error = suword32( + __DEVOLATILE(uint32_t *, &sem->_has_waiters), 0); + umtxq_lock(&key); + } + umtxq_unbusy(&key); + umtxq_unlock(&key); + umtx_key_release(&key); + return (error); +} + int _umtx_lock(struct thread *td, struct _umtx_lock_args *uap) /* struct umtx *umtx */ @@ -3031,6 +3135,35 @@ return do_rw_unlock(td, uap->obj); } +static int +__umtx_op_sem_wait(struct thread *td, struct _umtx_op_args *uap) +{ + struct timespec *ts, timeout; + int error; + + /* Allow a null timespec (wait forever). */ + if (uap->uaddr2 == NULL) + ts = NULL; + else { + error = copyin(uap->uaddr2, &timeout, + sizeof(timeout)); + if (error != 0) + return (error); + if (timeout.tv_nsec >= 1000000000 || + timeout.tv_nsec < 0) { + return (EINVAL); + } + ts = &timeout; + } + return (do_sem_wait(td, uap->obj, ts)); +} + +static int +__umtx_op_sem_wake(struct thread *td, struct _umtx_op_args *uap) +{ + return do_sem_wake(td, uap->obj); +} + typedef int (*_umtx_op_func)(struct thread *td, struct _umtx_op_args *uap); static _umtx_op_func op_table[] = { @@ -3052,7 +3185,9 @@ __umtx_op_wait_uint_private, /* UMTX_OP_WAIT_UINT_PRIVATE */ __umtx_op_wake_private, /* UMTX_OP_WAKE_PRIVATE */ __umtx_op_wait_umutex, /* UMTX_OP_UMUTEX_WAIT */ - __umtx_op_wake_umutex /* UMTX_OP_UMUTEX_WAKE */ + __umtx_op_wake_umutex, /* UMTX_OP_UMUTEX_WAKE */ + __umtx_op_sem_wait, /* UMTX_OP_SEM_WAIT */ + __umtx_op_sem_wake /* UMTX_OP_SEM_WAKE */ }; int @@ -3274,6 +3409,27 @@ return do_wait(td, uap->obj, uap->val, ts, 1, 1); } +static int +__umtx_op_sem_wait_compat32(struct thread *td, struct _umtx_op_args *uap) +{ + struct timespec *ts, timeout; + int error; + + /* Allow a null timespec (wait forever). */ + if (uap->uaddr2 == NULL) + ts = NULL; + else { + error = copyin_timeout32(uap->uaddr2, &timeout); + if (error != 0) + return (error); + if (timeout.tv_nsec >= 1000000000 || + timeout.tv_nsec < 0) + return (EINVAL); + ts = &timeout; + } + return (do_sem_wait(td, uap->obj, ts)); +} + static _umtx_op_func op_table_compat32[] = { __umtx_op_lock_umtx_compat32, /* UMTX_OP_LOCK */ __umtx_op_unlock_umtx_compat32, /* UMTX_OP_UNLOCK */ @@ -3293,7 +3449,9 @@ __umtx_op_wait_uint_private_compat32, /* UMTX_OP_WAIT_UINT_PRIVATE */ __umtx_op_wake_private, /* UMTX_OP_WAKE_PRIVATE */ __umtx_op_wait_umutex_compat32, /* UMTX_OP_UMUTEX_WAIT */ - __umtx_op_wake_umutex /* UMTX_OP_UMUTEX_WAKE */ + __umtx_op_wake_umutex, /* UMTX_OP_UMUTEX_WAKE */ + __umtx_op_sem_wait_compat32, /* UMTX_OP_SEM_WAIT */ + __umtx_op_sem_wake /* UMTX_OP_SEM_WAKE */ }; int Index: sys/kern/uipc_sem.c =================================================================== --- sys/kern/uipc_sem.c (revision 200821) +++ sys/kern/uipc_sem.c (working copy) @@ -51,7 +51,6 @@ #include #include #include -#include #include #include #include