summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ObsoleteFiles.inc2
-rw-r--r--include/Makefile4
-rw-r--r--include/semaphore.h64
-rw-r--r--lib/libc/gen/Makefile.inc2
-rw-r--r--lib/libc/gen/Symbol.map51
-rw-r--r--lib/libc/gen/_pthread_stubs.c4
-rw-r--r--lib/libc/gen/sem.c232
-rw-r--r--lib/libc/gen/sem_new.c470
-rw-r--r--lib/libc/include/libc_private.h2
-rw-r--r--lib/libthr/pthread.map21
-rw-r--r--lib/libthr/thread/Makefile.inc1
-rw-r--r--lib/libthr/thread/thr_init.c4
-rw-r--r--lib/libthr/thread/thr_private.h17
-rw-r--r--lib/libthr/thread/thr_sem.c258
-rw-r--r--lib/libthr/thread/thr_sem_new.c103
-rw-r--r--sys/kern/uipc_sem.c1
-rw-r--r--sys/sys/_semaphore.h21
-rw-r--r--sys/sys/semaphore.h69
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_ */
OpenPOWER on IntegriCloud