diff options
-rw-r--r-- | ObsoleteFiles.inc | 2 | ||||
-rw-r--r-- | include/Makefile | 4 | ||||
-rw-r--r-- | include/semaphore.h | 64 | ||||
-rw-r--r-- | lib/libc/gen/Makefile.inc | 2 | ||||
-rw-r--r-- | lib/libc/gen/Symbol.map | 51 | ||||
-rw-r--r-- | lib/libc/gen/_pthread_stubs.c | 4 | ||||
-rw-r--r-- | lib/libc/gen/sem.c | 232 | ||||
-rw-r--r-- | lib/libc/gen/sem_new.c | 470 | ||||
-rw-r--r-- | lib/libc/include/libc_private.h | 2 | ||||
-rw-r--r-- | lib/libthr/pthread.map | 21 | ||||
-rw-r--r-- | lib/libthr/thread/Makefile.inc | 1 | ||||
-rw-r--r-- | lib/libthr/thread/thr_init.c | 4 | ||||
-rw-r--r-- | lib/libthr/thread/thr_private.h | 17 | ||||
-rw-r--r-- | lib/libthr/thread/thr_sem.c | 258 | ||||
-rw-r--r-- | lib/libthr/thread/thr_sem_new.c | 103 | ||||
-rw-r--r-- | sys/kern/uipc_sem.c | 1 | ||||
-rw-r--r-- | sys/sys/_semaphore.h | 21 | ||||
-rw-r--r-- | sys/sys/semaphore.h | 69 |
18 files changed, 924 insertions, 402 deletions
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 52ca682..784c8de 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -14,6 +14,8 @@ # The file is partitioned: OLD_FILES first, then OLD_LIBS and OLD_DIRS last. # +# 20100105: new userland semaphore implementation +OLD_FILES+=usr/include/sys/semaphore.h # 20100103: ntptrace(8) removed OLD_FILES+=usr/sbin/ntptrace OLD_FILES+=usr/share/man/man8/ntptrace.8.gz diff --git a/include/Makefile b/include/Makefile index 2b0ea22..68a7e8d 100644 --- a/include/Makefile +++ b/include/Makefile @@ -18,7 +18,7 @@ INCS= a.out.h ar.h assert.h bitstring.h complex.h cpio.h _ctype.h ctype.h \ 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 @@ INCS= a.out.h ar.h assert.h bitstring.h complex.h cpio.h _ctype.h ctype.h \ 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 diff --git a/include/semaphore.h b/include/semaphore.h new file mode 100644 index 0000000..3531353 --- /dev/null +++ b/include/semaphore.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010 David Xu <davidxu@freebsd.org> + * + * 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 <sys/cdefs.h> +#include <sys/_types.h> +#include <sys/_umtx.h> + +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_ */ diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index d6b403e..2abfe57 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -25,7 +25,7 @@ SRCS+= __getosreldate.c __xuname.c \ 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_new.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 \ diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index a3ea75b..4f75b73 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -236,16 +236,6 @@ FBSD_1.0 { 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 @@ FBSD_1.1 { 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 @@ FBSDprivate_1.0 { __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 @@ FBSDprivate_1.0 { _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; }; diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c index 147235e..044e299e 100644 --- a/lib/libc/gen/_pthread_stubs.c +++ b/lib/libc/gen/_pthread_stubs.c @@ -119,6 +119,8 @@ pthread_func_entry_t __thr_jtable[PJT_MAX] = { {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_kill, PJT_KILL, int, void *, int) 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) diff --git a/lib/libc/gen/sem.c b/lib/libc/gen/sem.c index cd31d31..4ec7890 100644 --- a/lib/libc/gen/sem.c +++ b/lib/libc/gen/sem.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2010 David Xu <davidxu@freebsd.org>. * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. * All rights reserved. * @@ -59,34 +60,71 @@ #include "namespace.h" #include <sys/types.h> #include <sys/queue.h> +#include <machine/atomic.h> #include <errno.h> +#include <sys/umtx.h> +#include <sys/_semaphore.h> +#include <limits.h> #include <fcntl.h> #include <pthread.h> -#include <semaphore.h> #include <stdarg.h> #include <stdlib.h> #include <time.h> -#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 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 @@ static void 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_alloc(unsigned int value, semid_t semid, int system_sem) 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 @@ __sem_init(sem_t *sem, int pshared, unsigned int value) * 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 @@ __sem_destroy(sem_t *sem) 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 @@ err: } int -__sem_close(sem_t *sem) +_libc_sem_close_compat(sem_t *sem) { if (sem_check_validity(sem) != 0) @@ -280,68 +311,156 @@ __sem_close(sem_t *sem) } 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, NULL, __DECONST(void*, timeout)); +} - return (ksem_wait((*sem)->semid)); +static int +_umtx_wake(volatile void *mtx) +{ + return _umtx_op(__DEVOLATILE(void *, mtx), UMTX_OP_WAKE_PRIVATE, + 1, NULL, NULL); +} + +#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 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); + } + + retval = 0; + _pthread_testcancel(); + for (;;) { + while ((val = (*sem)->count) > 0) { + if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) + return (0); + } + if (retval) + break; + 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); } - _pthread_mutex_unlock(&(*sem)->lock); + 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); } return (retval); } 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 +470,7 @@ __sem_getvalue(sem_t * __restrict sem, int * __restrict sval) 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); diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c new file mode 100644 index 0000000..dac5381 --- /dev/null +++ b/lib/libc/gen/sem_new.c @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2010 David Xu <davidxu@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), 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 COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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$ + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <errno.h> +#include <machine/atomic.h> +#include <sys/umtx.h> +#include <limits.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <semaphore.h> +#include <unistd.h> +#include "un-namespace.h" + +__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); + +#define SEM_PREFIX "/tmp/SEMD" +#define SEM_MAGIC ((u_int32_t)0x73656d31) + +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 void +sem_prefork() +{ + + _pthread_mutex_lock(&sem_llock); +} + +static void +sem_postfork() +{ + _pthread_mutex_unlock(&sem_llock); +} + +static void +sem_child_postfork() +{ + _pthread_mutex_unlock(&sem_llock); +} + +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 inline int +sem_check_validity(sem_t *sem) +{ + + if (sem->_magic == SEM_MAGIC) + return (0); + else { + errno = EINVAL; + return (-1); + } +} + +int +_libc_sem_init(sem_t *sem, int pshared, unsigned int value) +{ + + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + 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); +} + +sem_t * +_libc_sem_open(const char *name, int flags, ...) +{ + char path[PATH_MAX]; + + struct stat sb; + va_list ap; + struct sem_nameinfo *ni = NULL; + sem_t *sem = NULL; + int fd = -1, mode, len; + + if (name[0] != '/') { + errno = EINVAL; + return (NULL); + } + name++; + + if (flags & ~(O_CREAT|O_EXCL)) { + errno = EINVAL; + return (NULL); + } + + _pthread_once(&once, sem_module_init); + + _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 (flags & O_CREAT) { + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + } + + 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; + } + } + 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; + 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 +_libc_sem_close(sem_t *sem) +{ + struct sem_nameinfo *ni; + + if (sem_check_validity(sem) != 0) + return (-1); + + if (!(sem->_kern._flags & SEM_NAMED)) { + errno = EINVAL; + 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; + } + } + + 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 +_libc_sem_unlink(const char *name) +{ + char path[PATH_MAX]; + + 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 +_libc_sem_destroy(sem_t *sem) +{ + + if (sem_check_validity(sem) != 0) + return (-1); + + if (sem->_kern._flags & SEM_NAMED) { + errno = EINVAL; + return (-1); + } + sem->_magic = 0; + return (0); +} + +int +_libc_sem_getvalue(sem_t * __restrict sem, int * __restrict sval) +{ + + if (sem_check_validity(sem) != 0) + return (-1); + + *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 _umtx_op(sem, UMTX_OP_SEM_WAIT, 0, NULL, + __DECONST(void*, timeout)); +} + +int +_libc_sem_trywait(sem_t *sem) +{ + int val; + + if (sem_check_validity(sem) != 0) + return (-1); + + 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 +_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); + + retval = 0; + _pthread_testcancel(); + for (;;) { + while ((val = sem->_kern._count) > 0) { + if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1)) + return (0); + } + + if (retval) + break; + + /* + * 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); + } + return (retval); +} + +int +_libc_sem_wait(sem_t *sem) +{ + 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); + + atomic_add_rel_int(&sem->_kern._count, 1); + if (sem->_kern._has_waiters) + return usem_wake(&sem->_kern); + return (0); +} diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h index 052eb13..cb0b407 100644 --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -127,6 +127,8 @@ typedef enum { PJT_SETSPECIFIC, PJT_SIGMASK, PJT_TESTCANCEL, + PJT_CLEANUP_POP_IMP, + PJT_CLEANUP_PUSH_IMP, PJT_MAX } pjt_index_t; diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map index 62f3ff5..0ade298 100644 --- a/lib/libthr/pthread.map +++ b/lib/libthr/pthread.map @@ -145,13 +145,6 @@ FBSD_1.0 { recvfrom; recvmsg; select; - sem_destroy; - sem_getvalue; - sem_init; - sem_post; - sem_timedwait; - sem_trywait; - sem_wait; sendmsg; sendto; sigaction; @@ -348,13 +341,6 @@ FBSDprivate_1.0 { _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.1 { FBSD_1.2 { openat; + sem_destroy; + sem_getvalue; + sem_init; + sem_post; + sem_timedwait; + sem_trywait; + sem_wait; }; diff --git a/lib/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc index 4ce90b5..d3de74e 100644 --- a/lib/libthr/thread/Makefile.inc +++ b/lib/libthr/thread/Makefile.inc @@ -41,6 +41,7 @@ SRCS+= \ thr_rwlockattr.c \ thr_self.c \ thr_sem.c \ + thr_sem_new.c \ thr_setprio.c \ thr_setschedparam.c \ thr_sig.c \ diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c index f96bba9..1bfdd28 100644 --- a/lib/libthr/thread/thr_init.c +++ b/lib/libthr/thread/thr_init.c @@ -246,7 +246,9 @@ static pthread_func_t jmp_table[][2] = { {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; diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h index 57be0ae..415c1ec 100644 --- a/lib/libthr/thread/thr_private.h +++ b/lib/libthr/thread/thr_private.h @@ -52,6 +52,20 @@ #include <sys/thr.h> #include <pthread.h> +#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 @@ int _schedparam_to_rtp(int policy, const struct sched_param *param, 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); diff --git a/lib/libthr/thread/thr_sem.c b/lib/libthr/thread/thr_sem.c index 0dd5599..f20bde3 100644 --- a/lib/libthr/thread/thr_sem.c +++ b/lib/libthr/thread/thr_sem.c @@ -36,7 +36,6 @@ #include <errno.h> #include <fcntl.h> #include <pthread.h> -#include <semaphore.h> #include <stdlib.h> #include <time.h> #include <_semaphore.h> @@ -44,248 +43,73 @@ #include "thr_private.h" - -__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); - - -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); -} +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); + +typedef struct sem *sem_t; + +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); 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) -{ - 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); -} - -static void -sem_cancel_handler(void *arg) +_sem_trywait_compat(sem_t *sem) { - sem_t *sem = arg; - - atomic_add_int(&(*sem)->nwaiters, -1); - if ((*sem)->nwaiters && (*sem)->count) - _thr_umtx_wake(&(*sem)->count, 1, 0); + return _libc_sem_trywait_compat(sem); } 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); } diff --git a/lib/libthr/thread/thr_sem_new.c b/lib/libthr/thread/thr_sem_new.c new file mode 100644 index 0000000..689b252 --- /dev/null +++ b/lib/libthr/thread/thr_sem_new.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2010 David Xu <davidxu@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), 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 COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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$ + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/queue.h> +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdlib.h> +#include <time.h> +#include <semaphore.h> +#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); +__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(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); + +int +_sem_init(sem_t *sem, int pshared, unsigned int value) +{ + return _libc_sem_init(sem, pshared, value); +} + +int +_sem_destroy(sem_t *sem) +{ + return _libc_sem_destroy(sem); +} + +int +_sem_getvalue(sem_t * __restrict sem, int * __restrict sval) +{ + return _libc_sem_getvalue(sem, sval); +} + +int +_sem_trywait(sem_t *sem) +{ + return _libc_sem_trywait(sem); +} + +int +_sem_wait(sem_t *sem) +{ + return _libc_sem_wait(sem); +} + +int +_sem_timedwait(sem_t * __restrict sem, + const struct timespec * __restrict abstime) +{ + return _libc_sem_timedwait(sem, abstime); +} + +int +_sem_post(sem_t *sem) +{ + return _libc_sem_post(sem); +} diff --git a/sys/kern/uipc_sem.c b/sys/kern/uipc_sem.c index 5ca13f8..f41b49c 100644 --- a/sys/kern/uipc_sem.c +++ b/sys/kern/uipc_sem.c @@ -51,7 +51,6 @@ __FBSDID("$FreeBSD$"); #include <sys/priv.h> #include <sys/proc.h> #include <sys/posix4.h> -#include <sys/semaphore.h> #include <sys/_semaphore.h> #include <sys/stat.h> #include <sys/syscall.h> diff --git a/sys/sys/_semaphore.h b/sys/sys/_semaphore.h index df3c5da..5266d04 100644 --- a/sys/sys/_semaphore.h +++ b/sys/sys/_semaphore.h @@ -31,26 +31,9 @@ typedef intptr_t semid_t; struct timespec; -#ifndef _KERNEL - -#include <sys/cdefs.h> +#define SEM_VALUE_MAX __INT_MAX -/* - * 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; -}; +#ifndef _KERNEL __BEGIN_DECLS diff --git a/sys/sys/semaphore.h b/sys/sys/semaphore.h deleted file mode 100644 index 34ede7b..0000000 --- a/sys/sys/semaphore.h +++ /dev/null @@ -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 <machine/_limits.h> - -/* 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 <sys/cdefs.h> - -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_ */ |