diff options
author | 2017-09-05 02:40:54 +0000 | |
---|---|---|
committer | 2017-09-05 02:40:54 +0000 | |
commit | a5511fa9f431600dbd6dc2b46fc4e6b73e7d239c (patch) | |
tree | bf9e27f29ab35e6599d4c1362a9902d7e7bfdc74 /lib | |
parent | Serialize access to IP reassembly queue with a mutex. This lets (diff) | |
download | wireguard-openbsd-a5511fa9f431600dbd6dc2b46fc4e6b73e7d239c.tar.xz wireguard-openbsd-a5511fa9f431600dbd6dc2b46fc4e6b73e7d239c.zip |
Move mutex, condvar, and thread-specific data routes, pthread_once, and
pthread_exit from libpthread to libc, along with low-level bits to
support them. Major bump to both libc and libpthread.
Requested by libressl team. Ports testing by naddy@
ok kettenis@
Diffstat (limited to 'lib')
52 files changed, 504 insertions, 3856 deletions
diff --git a/lib/libc/Symbols.list b/lib/libc/Symbols.list index bba27bc4d54..ed44e82197b 100644 --- a/lib/libc/Symbols.list +++ b/lib/libc/Symbols.list @@ -25,6 +25,7 @@ __thrsigdivert __thrsleep __thrwakeup _exit +_thread_canceled _thread_sys___get_tcb _thread_sys___getcwd _thread_sys___semctl @@ -1613,9 +1614,38 @@ tcsetattr tcsetpgrp /* thread */ +_rthread_debug +_spinlock +_spinlocktry +_spinunlock _thread_atfork +_thread_dofork _thread_set_callbacks pthread_atfork +pthread_cond_broadcast +pthread_cond_destroy +pthread_cond_init +pthread_cond_signal +pthread_cond_timedwait +pthread_cond_wait +pthread_condattr_destroy +pthread_condattr_getclock +pthread_condattr_init +pthread_condattr_setclock +pthread_equal +pthread_exit +pthread_getspecific +pthread_key_create +pthread_key_delete +pthread_mutex_destroy +pthread_mutex_init +pthread_mutex_lock +pthread_mutex_timedlock +pthread_mutex_trylock +pthread_mutex_unlock +pthread_once +pthread_self +pthread_setspecific /* time */ asctime diff --git a/lib/librthread/rthread_once.c b/lib/libc/hidden/machine/spinlock.h index cb5ea8a948f..26a7c30b265 100644 --- a/lib/librthread/rthread_once.c +++ b/lib/libc/hidden/machine/spinlock.h @@ -1,7 +1,6 @@ -/* $OpenBSD: rthread_once.c,v 1.1 2011/12/21 23:59:03 guenther Exp $ */ +/* $OpenBSD: spinlock.h,v 1.1 2017/09/05 02:40:54 guenther Exp $ */ /* - * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> - * All Rights Reserved. + * Copyright (c) 2017 Philip Guenther <guenther@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,17 +15,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <pthread.h> +#ifndef _LIBC_MACHINE_SPINLOCK_H_ +#define _LIBC_MACHINE_SPINLOCK_H_ -int -pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) -{ - pthread_mutex_lock(&once_control->mutex); - if (once_control->state == PTHREAD_NEEDS_INIT) { - init_routine(); - once_control->state = PTHREAD_DONE_INIT; - } - pthread_mutex_unlock(&once_control->mutex); +#include_next <machine/spinlock.h> - return (0); -} +__BEGIN_HIDDEN_DECLS +int _atomic_lock(volatile _atomic_lock_t *); +__END_HIDDEN_DECLS + +#endif /* !_LIBC_MACHINE_SPINLOCK_H_ */ diff --git a/lib/libc/hidden/pthread.h b/lib/libc/hidden/pthread.h index c390753a1c2..534020101c5 100644 --- a/lib/libc/hidden/pthread.h +++ b/lib/libc/hidden/pthread.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pthread.h,v 1.1 2015/11/10 04:14:03 guenther Exp $ */ +/* $OpenBSD: pthread.h,v 1.2 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2015 Philip Guenther <guenther@openbsd.org> * @@ -20,6 +20,29 @@ #include_next <pthread.h> -PROTO_DEPRECATED(pthread_atfork); +PROTO_STD_DEPRECATED(pthread_atfork); +PROTO_STD_DEPRECATED(pthread_cond_broadcast); +PROTO_STD_DEPRECATED(pthread_cond_destroy); +PROTO_NORMAL(pthread_cond_init); +PROTO_STD_DEPRECATED(pthread_cond_signal); +PROTO_STD_DEPRECATED(pthread_cond_timedwait); +PROTO_STD_DEPRECATED(pthread_cond_wait); +PROTO_STD_DEPRECATED(pthread_condattr_destroy); +PROTO_STD_DEPRECATED(pthread_condattr_getclock); +PROTO_STD_DEPRECATED(pthread_condattr_init); +PROTO_STD_DEPRECATED(pthread_condattr_setclock); +PROTO_NORMAL(pthread_exit); +PROTO_NORMAL(pthread_getspecific); +PROTO_NORMAL(pthread_key_create); +PROTO_STD_DEPRECATED(pthread_key_delete); +PROTO_NORMAL(pthread_mutex_destroy); +PROTO_NORMAL(pthread_mutex_init); +PROTO_NORMAL(pthread_mutex_lock); +PROTO_STD_DEPRECATED(pthread_mutex_timedlock); +PROTO_STD_DEPRECATED(pthread_mutex_trylock); +PROTO_NORMAL(pthread_mutex_unlock); +PROTO_STD_DEPRECATED(pthread_once); +PROTO_NORMAL(pthread_self); +PROTO_NORMAL(pthread_setspecific); #endif /* !_LIBC_PTHREAD_H_ */ diff --git a/lib/libc/include/cancel.h b/lib/libc/include/cancel.h index 2c87be39e3f..c452bf3d4cf 100644 --- a/lib/libc/include/cancel.h +++ b/lib/libc/include/cancel.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cancel.h,v 1.4 2017/04/20 17:16:32 visa Exp $ */ +/* $OpenBSD: cancel.h,v 1.5 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2015 Philip Guenther <guenther@openbsd.org> * @@ -21,10 +21,12 @@ #include <tib.h> #include "thread_private.h" -__BEGIN_HIDDEN_DECLS /* process a cancel request at a cancel point */ __dead void _thread_canceled(void); -__END_HIDDEN_DECLS + +#ifdef __LIBC__ +PROTO_NORMAL(_thread_canceled); +#endif #if defined(__LIBC__) && !defined(TCB_HAVE_MD_GET) /* diff --git a/lib/libc/include/thread_private.h b/lib/libc/include/thread_private.h index b443e32e837..23faa73faaf 100644 --- a/lib/libc/include/thread_private.h +++ b/lib/libc/include/thread_private.h @@ -1,4 +1,4 @@ -/* $OpenBSD: thread_private.h,v 1.29 2016/10/15 18:24:40 guenther Exp $ */ +/* $OpenBSD: thread_private.h,v 1.30 2017/09/05 02:40:54 guenther Exp $ */ /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ @@ -57,7 +57,13 @@ PROTO_NORMAL(_malloc_init); * If not NULL, they are called instead of the syscall stub, so that * the thread library can do necessary locking and reinitialization. * + * tc_thread_release: + * Handles the release of a thread's TIB and struct pthread and the + * notification of other threads...when there are other threads. * + * tc_thread_key_zero: + * For each thread, zero out the key data associated with the given key. + * If <machine/tcb.h> doesn't define TCB_GET(), then locating the TCB in a * threaded process requires a syscall (__get_tcb(2)) which is too much * overhead for single-threaded processes. For those archs, there are two @@ -71,6 +77,7 @@ PROTO_NORMAL(_malloc_init); * Returns the address of the thread's TCB. */ +struct pthread; struct thread_callbacks { int *(*tc_errnoptr)(void); /* MUST BE FIRST */ void *(*tc_tcb)(void); @@ -94,6 +101,8 @@ struct thread_callbacks { void *(*tc_tag_storage)(void **, void *, size_t, void *); __pid_t (*tc_fork)(void); __pid_t (*tc_vfork)(void); + void (*tc_thread_release)(struct pthread *); + void (*tc_thread_key_zero)(int); }; __BEGIN_PUBLIC_DECLS @@ -116,13 +125,6 @@ __END_HIDDEN_DECLS #define __THREAD_NAME(name) __CONCAT(_thread_tagname_,name) /* - * Resolver code is special cased in that it uses global keys. - */ -extern void *__THREAD_NAME(_res); -extern void *__THREAD_NAME(_res_ext); -extern void *__THREAD_NAME(serv_mutex); - -/* * Macros used in libc to access thread mutex, keys, and per thread storage. * _THREAD_PRIVATE_KEY and _THREAD_PRIVATE_MUTEX are different macros for * historical reasons. They do the same thing, define a static variable @@ -235,4 +237,171 @@ extern void *__THREAD_NAME(serv_mutex); } while (0) #endif /* __LIBC__ */ + +/* + * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Private data structures that back up the typedefs in pthread.h. + * Since only the thread library cares about their size or arrangement, + * it should be possible to switch libraries without relinking. + * + * Do not reorder _atomic_lock_t and sem_t variables in the structs. + * This is due to alignment requirements of certain arches like hppa. + * The current requirement is 16 bytes. + * + * THE MACHINE DEPENDENT CERROR CODE HAS HARD CODED OFFSETS INTO PTHREAD_T! + */ + +#include <sys/queue.h> +#include <pthread.h> +#include <semaphore.h> +#include <machine/spinlock.h> + +#define _SPINLOCK_UNLOCKED _ATOMIC_LOCK_UNLOCKED + +struct __sem { + _atomic_lock_t lock; + volatile int waitcount; + volatile int value; + int shared; +}; + +TAILQ_HEAD(pthread_queue, pthread); + +#ifdef FUTEX + +struct pthread_mutex { + volatile unsigned int lock; + int type; + pthread_t owner; + int count; + int prioceiling; +}; + +struct pthread_cond { + volatile unsigned int seq; + clockid_t clock; + struct pthread_mutex *mutex; +}; + +#else + +struct pthread_mutex { + _atomic_lock_t lock; + struct pthread_queue lockers; + int type; + pthread_t owner; + int count; + int prioceiling; +}; + +struct pthread_cond { + _atomic_lock_t lock; + struct pthread_queue waiters; + struct pthread_mutex *mutex; + clockid_t clock; +}; +#endif /* FUTEX */ + +struct pthread_mutex_attr { + int ma_type; + int ma_protocol; + int ma_prioceiling; +}; + +struct pthread_cond_attr { + clockid_t ca_clock; +}; + +struct pthread_attr { + void *stack_addr; + size_t stack_size; + size_t guard_size; + int detach_state; + int contention_scope; + int sched_policy; + struct sched_param sched_param; + int sched_inherit; +}; + +struct rthread_storage { + int keyid; + struct rthread_storage *next; + void *data; +}; + +struct rthread_cleanup_fn { + void (*fn)(void *); + void *arg; + struct rthread_cleanup_fn *next; +}; + +struct tib; +struct stack; +struct pthread { + struct __sem donesem; + unsigned int flags; + _atomic_lock_t flags_lock; + struct tib *tib; + void *retval; + void *(*fn)(void *); + void *arg; + char name[32]; + struct stack *stack; + LIST_ENTRY(pthread) threads; + TAILQ_ENTRY(pthread) waiting; + pthread_cond_t blocking_cond; + struct pthread_attr attr; + struct rthread_storage *local_storage; + struct rthread_cleanup_fn *cleanup_fns; + + /* cancel received in a delayed cancel block? */ + int delayed_cancel; +}; +/* flags in pthread->flags */ +#define THREAD_DONE 0x001 +#define THREAD_DETACHED 0x002 + +/* flags in tib->tib_thread_flags */ +#define TIB_THREAD_ASYNC_CANCEL 0x001 +#define TIB_THREAD_INITIAL_STACK 0x002 /* has stack from exec */ + +#define ENTER_DELAYED_CANCEL_POINT(tib, self) \ + (self)->delayed_cancel = 0; \ + ENTER_CANCEL_POINT_INNER(tib, 1, 1) + +/* + * Internal functions exported from libc's thread bits for use by libpthread + */ +void _spinlock(volatile _atomic_lock_t *); +int _spinlocktry(volatile _atomic_lock_t *); +void _spinunlock(volatile _atomic_lock_t *); + +void _rthread_debug(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +pid_t _thread_dofork(pid_t (*_sys_fork)(void)); + +/* + * Threading syscalls not declared in system headers + */ +__dead void __threxit(pid_t *); +int __thrsleep(const volatile void *, clockid_t, + const struct timespec *, volatile void *, const int *); +int __thrwakeup(const volatile void *, int n); +int __thrsigdivert(sigset_t, siginfo_t *, const struct timespec *); + #endif /* _THREAD_PRIVATE_H_ */ diff --git a/lib/libc/shlib_version b/lib/libc/shlib_version index dba8c777a39..c15952cf991 100644 --- a/lib/libc/shlib_version +++ b/lib/libc/shlib_version @@ -1,4 +1,4 @@ -major=89 -minor=6 +major=90 +minor=0 # note: If changes were made to include/thread_private.h or if system # calls were added/changed then librthread/shlib_version also be updated. diff --git a/lib/libc/sys/canceled.c b/lib/libc/sys/canceled.c index 7bf02c93552..3d3da57f2cf 100644 --- a/lib/libc/sys/canceled.c +++ b/lib/libc/sys/canceled.c @@ -24,4 +24,4 @@ _thread_canceled(void) _thread_cb.tc_canceled(); exit(0); } - +DEF_STRONG(_thread_canceled); diff --git a/lib/libc/thread/Makefile.inc b/lib/libc/thread/Makefile.inc index 8c0cecf92d7..b409f578e3e 100644 --- a/lib/libc/thread/Makefile.inc +++ b/lib/libc/thread/Makefile.inc @@ -1,5 +1,36 @@ -# $OpenBSD: Makefile.inc,v 1.10 2016/05/07 19:05:22 guenther Exp $ +# $OpenBSD: Makefile.inc,v 1.11 2017/09/05 02:40:54 guenther Exp $ .PATH: ${LIBCSRCDIR}/thread SRCS+= callbacks.c atfork.c + +# threads infrastructure +SRCS+= rthread.c \ + rthread_condattr.c \ + rthread_debug.c \ + rthread_file.c \ + rthread_libc.c \ + rthread_once.c \ + rthread_tls.c \ + +notyet= rthread_condattr_clock.c \ + rthread_equal.c \ + rthread_exit.c \ + spinlock.c \ + spinlocktry.c + +.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" || \ + ${MACHINE_ARCH} == "mips64" || ${MACHINE_ARCH} == "mips64el" +CFLAGS+= -DFUTEX +SRCS+= rthread_mutex.c \ + rthread_cond.c +.else +SRCS+= rthread_sync.c +.endif + +.if defined(NOPIC) +CFLAGS+=-DNO_PIC +.endif + +OBJS+= _atomic_lock.o + diff --git a/lib/libc/thread/callbacks.c b/lib/libc/thread/callbacks.c index c76811dd246..e38cf205a54 100644 --- a/lib/libc/thread/callbacks.c +++ b/lib/libc/thread/callbacks.c @@ -14,12 +14,20 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <pthread.h> #include <signal.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include "thread_private.h" +#include "rthread_cb.h" + +static __dead void +_thread_canceled(void) +{ + pthread_exit(PTHREAD_CANCELED); +} void _thread_set_callbacks(const struct thread_callbacks *cb, size_t len) @@ -37,6 +45,30 @@ _thread_set_callbacks(const struct thread_callbacks *cb, size_t len) if (sigprocmask(SIG_BLOCK, &allmask, &omask) == 0) { /* mprotect RW */ memcpy(&_thread_cb, cb, sizeof(_thread_cb)); + + /* + * These are supplied by libc, but only enabled + * here when we actually need to prep for doing MT. + */ + _thread_cb.tc_canceled = _thread_canceled; + _thread_cb.tc_flockfile = _thread_flockfile; + _thread_cb.tc_ftrylockfile = _thread_ftrylockfile; + _thread_cb.tc_funlockfile = _thread_funlockfile; + _thread_cb.tc_malloc_lock = _thread_malloc_lock; + _thread_cb.tc_malloc_unlock = _thread_malloc_unlock; + _thread_cb.tc_atexit_lock = _thread_atexit_lock; + _thread_cb.tc_atexit_unlock = _thread_atexit_unlock; + _thread_cb.tc_atfork_lock = _thread_atfork_lock; + _thread_cb.tc_atfork_unlock = _thread_atfork_unlock; + _thread_cb.tc_arc4_lock = _thread_arc4_lock; + _thread_cb.tc_arc4_unlock = _thread_arc4_unlock; + _thread_cb.tc_mutex_lock = _thread_mutex_lock; + _thread_cb.tc_mutex_unlock = _thread_mutex_unlock; + _thread_cb.tc_mutex_destroy = _thread_mutex_destroy; + _thread_cb.tc_tag_lock = _thread_tag_lock; + _thread_cb.tc_tag_unlock = _thread_tag_unlock; + _thread_cb.tc_tag_storage = _thread_tag_storage; + /* mprotect RO | LOCKPERM | NOUNMAP */ sigprocmask(SIG_SETMASK, &omask, NULL); } diff --git a/lib/libc/thread/rthread.c b/lib/libc/thread/rthread.c index 97947e515df..0f19338b086 100644 --- a/lib/libc/thread/rthread.c +++ b/lib/libc/thread/rthread.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread.c,v 1.3 2017/08/15 07:06:29 guenther Exp $ */ +/* $OpenBSD: rthread.c,v 1.4 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * All Rights Reserved. @@ -16,71 +16,25 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* - * The heart of rthreads. Basic functions like creating and joining - * threads. + * The infrastructure of rthreads */ -#include <sys/types.h> -#ifndef NO_PIC -#include <sys/exec_elf.h> -#pragma weak _DYNAMIC -#endif - -#include <dlfcn.h> -#include <errno.h> #include <pthread.h> -#include <signal.h> -#include <stdio.h> #include <stdlib.h> -#include <string.h> #include <tib.h> #include <unistd.h> -#include "cancel.h" /* in libc/include */ -#include "thread_private.h" #include "rthread.h" -#include "rthread_cb.h" - -/* - * Call nonstandard functions via names in the reserved namespace: - * dlctl() -> _dlctl() - * getthrid -> _thread_sys_getthrid - */ -typeof(dlctl) dlctl asm("_dlctl") __attribute__((weak)); -REDIRECT_SYSCALL(getthrid); - -/* weak stub to be overriden by ld.so */ -int dlctl(void *handle, int cmd, void *data) { return 0; } -/* - * libc's signal wrappers hide SIGTHR; we need to call the real syscall - * stubs _thread_sys_* directly. - */ -REDIRECT_SYSCALL(sigaction); -REDIRECT_SYSCALL(sigprocmask); -REDIRECT_SYSCALL(thrkill); +#define RTHREAD_ENV_DEBUG "RTHREAD_DEBUG" -static int concurrency_level; /* not used */ +int _rthread_debug_level; -int _threads_ready; -int _post_threaded; -size_t _thread_pagesize; -struct listhead _thread_list = LIST_HEAD_INITIALIZER(_thread_list); -_atomic_lock_t _thread_lock = _SPINLOCK_UNLOCKED; -static struct pthread_queue _thread_gc_list - = TAILQ_HEAD_INITIALIZER(_thread_gc_list); -static _atomic_lock_t _thread_gc_lock = _SPINLOCK_UNLOCKED; -static struct pthread _initial_thread; +static int _threads_inited; -struct pthread_attr _rthread_attr_default = { - .stack_addr = NULL, - .stack_size = RTHREAD_STACK_SIZE_DEF, -/* .guard_size set in _rthread_init */ - .detach_state = PTHREAD_CREATE_JOINABLE, - .contention_scope = PTHREAD_SCOPE_SYSTEM, - .sched_policy = SCHED_OTHER, - .sched_param = { .sched_priority = 0 }, - .sched_inherit = PTHREAD_INHERIT_SCHED, +struct pthread _initial_thread = { + .flags_lock = _SPINLOCK_UNLOCKED, + .name = "Original thread", }; /* @@ -92,6 +46,7 @@ _spinlock(volatile _atomic_lock_t *lock) while (_atomic_lock(lock)) sched_yield(); } +DEF_STRONG(_spinlock); int _spinlocktry(volatile _atomic_lock_t *lock) @@ -104,82 +59,16 @@ _spinunlock(volatile _atomic_lock_t *lock) { *lock = _ATOMIC_LOCK_UNLOCKED; } +DEF_STRONG(_spinunlock); static void -_rthread_start(void *v) -{ - pthread_t thread = v; - void *retval; - - retval = thread->fn(thread->arg); - pthread_exit(retval); -} - -static void -sigthr_handler(__unused int sig) -{ - struct tib *tib = TIB_GET(); - pthread_t self = tib->tib_thread; - - /* - * Do nothing unless - * 1) pthread_cancel() has been called on this thread, - * 2) cancelation is enabled for it, and - * 3) we're not already in cancelation processing - */ - if (!tib->tib_canceled || tib->tib_cantcancel) - return; - - /* - * If delaying cancels inside complex ops (pthread_cond_wait, - * pthread_join, etc), just mark that this has happened to - * prevent a race with going to sleep - */ - if (tib->tib_cancel_point & CANCEL_POINT_DELAYED) { - self->delayed_cancel = 1; - return; - } - - /* - * otherwise, if in a cancel point or async cancels are - * enabled, then exit - */ - if (tib->tib_cancel_point || - (tib->tib_thread_flags & TIB_THREAD_ASYNC_CANCEL)) - pthread_exit(PTHREAD_CANCELED); -} - - -/* - * A few basic callbacks for libc. The first couple are only used - * on archs where there isn't a fast TCB_GET() - */ -#ifndef TCB_HAVE_MD_GET -static int * -multi_threaded_errnoptr(void) -{ - return (&TIB_GET()->tib_errno); -} - -static void * -multi_threaded_tcb(void) -{ - return (TCB_GET()); -} -#endif /* TCB_HAVE_MD_GET */ - -void -_thread_canceled(void) -{ - pthread_exit(PTHREAD_CANCELED); -} - -void _rthread_init(void) { pthread_t thread = &_initial_thread; struct tib *tib; - struct sigaction sa; + + if (_threads_inited) + return; tib = TIB_GET(); tib->tib_thread = thread; @@ -187,76 +76,24 @@ _rthread_init(void) thread->donesem.lock = _SPINLOCK_UNLOCKED; tib->tib_thread_flags = TIB_THREAD_INITIAL_STACK; - thread->flags_lock = _SPINLOCK_UNLOCKED; - strlcpy(thread->name, "Main process", sizeof(thread->name)); - LIST_INSERT_HEAD(&_thread_list, thread, threads); - _rthread_debug_init(); - - _thread_pagesize = (size_t)sysconf(_SC_PAGESIZE); - _rthread_attr_default.guard_size = _thread_pagesize; - thread->attr = _rthread_attr_default; - - /* get libc to start using our callbacks */ - { - struct thread_callbacks cb = { 0 }; - -#ifndef TCB_HAVE_MD_GET - cb.tc_errnoptr = multi_threaded_errnoptr; - cb.tc_tcb = multi_threaded_tcb; -#endif - cb.tc_canceled = _thread_canceled; - cb.tc_flockfile = _thread_flockfile; - cb.tc_ftrylockfile = _thread_ftrylockfile; - cb.tc_funlockfile = _thread_funlockfile; - cb.tc_malloc_lock = _thread_malloc_lock; - cb.tc_malloc_unlock = _thread_malloc_unlock; - cb.tc_atexit_lock = _thread_atexit_lock; - cb.tc_atexit_unlock = _thread_atexit_unlock; - cb.tc_atfork_lock = _thread_atfork_lock; - cb.tc_atfork_unlock = _thread_atfork_unlock; - cb.tc_arc4_lock = _thread_arc4_lock; - cb.tc_arc4_unlock = _thread_arc4_unlock; - cb.tc_mutex_lock = _thread_mutex_lock; - cb.tc_mutex_unlock = _thread_mutex_unlock; - cb.tc_mutex_destroy = _thread_mutex_destroy; - cb.tc_tag_lock = _thread_tag_lock; - cb.tc_tag_unlock = _thread_tag_unlock; - cb.tc_tag_storage = _thread_tag_storage; - cb.tc_fork = _thread_fork; - cb.tc_vfork = _thread_vfork; - _thread_set_callbacks(&cb, sizeof(cb)); - } - -#ifndef NO_PIC - if (_DYNAMIC) { - dlctl(NULL, DL_SETTHREADLCK, _rthread_dl_lock); - } -#endif /* - * Set the handler on the signal used for cancelation and - * suspension, and make sure it's unblocked + * Set the debug level from an environment string. + * Bogus values are silently ignored. */ - memset(&sa, 0, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_handler = sigthr_handler; - sigaction(SIGTHR, &sa, NULL); - sigaddset(&sa.sa_mask, SIGTHR); - sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL); - - _threads_ready = 1; + if (! issetugid()) { + char *envp = getenv(RTHREAD_ENV_DEBUG); - _malloc_init(1); + if (envp != NULL) { + char *rem; - _rthread_debug(1, "rthread init\n"); -} + _rthread_debug_level = (int) strtol(envp, &rem, 0); + if (*rem != '\0' || _rthread_debug_level < 0) + _rthread_debug_level = 0; + } + } -static void -_rthread_free(pthread_t thread) -{ - _spinlock(&_thread_gc_lock); - TAILQ_INSERT_TAIL(&_thread_gc_list, thread, waiting); - _spinunlock(&_thread_gc_lock); + _threads_inited = 1; } /* @@ -265,51 +102,21 @@ _rthread_free(pthread_t thread) pthread_t pthread_self(void) { - if (!_threads_ready) + if (__predict_false(!_threads_inited)) _rthread_init(); - return (TIB_GET()->tib_thread); + return TIB_GET()->tib_thread; } DEF_STRONG(pthread_self); -static void -_rthread_reaper(void) -{ - pthread_t thread; - -restart: - _spinlock(&_thread_gc_lock); - TAILQ_FOREACH(thread, &_thread_gc_list, waiting) { - if (thread->tib->tib_tid != 0) - continue; - TAILQ_REMOVE(&_thread_gc_list, thread, waiting); - _spinunlock(&_thread_gc_lock); - if (thread != &_initial_thread) { - _rthread_debug(3, "rthread reaping %p stack %p\n", - (void *)thread, (void *)thread->stack); - _rthread_free_stack(thread->stack); - _dl_free_tib(thread->tib, sizeof(*thread)); - } else { - /* initial thread isn't part of TIB allocation */ - _rthread_debug(3, "rthread reaping %p (initial)\n", - (void *)thread); - _dl_free_tib(thread->tib, 0); - } - goto restart; - } - _spinunlock(&_thread_gc_lock); -} - void pthread_exit(void *retval) { struct rthread_cleanup_fn *clfn; - struct tib *tib = TIB_GET(); - pthread_t thread; + struct tib *tib; + pthread_t thread = pthread_self(); - if (!_threads_ready) - _rthread_init(); - thread = tib->tib_thread; + tib = thread->tib; if (tib->tib_cantcancel & CANCEL_DYING) { /* @@ -331,19 +138,9 @@ pthread_exit(void *retval) free(oclfn); } _rthread_tls_destructors(thread); - _spinlock(&_thread_lock); - LIST_REMOVE(thread, threads); - _spinunlock(&_thread_lock); - _spinlock(&thread->flags_lock); - if (thread->flags & THREAD_DETACHED) { - _spinunlock(&thread->flags_lock); - _rthread_free(thread); - } else { - thread->flags |= THREAD_DONE; - _spinunlock(&thread->flags_lock); - _sem_post(&thread->donesem); - } + if (_thread_cb.tc_thread_release != NULL) + _thread_cb.tc_thread_release(thread); __threxit(&tib->tib_tid); for(;;); @@ -351,341 +148,8 @@ pthread_exit(void *retval) DEF_STRONG(pthread_exit); int -pthread_join(pthread_t thread, void **retval) -{ - int e; - struct tib *tib = TIB_GET(); - pthread_t self; - PREP_CANCEL_POINT(tib); - - if (_post_threaded) { -#define GREATSCOTT "great scott! serious repercussions on future events!\n" - write(2, GREATSCOTT, sizeof(GREATSCOTT) - 1); - abort(); - } - if (!_threads_ready) - _rthread_init(); - self = tib->tib_thread; - - e = 0; - ENTER_DELAYED_CANCEL_POINT(tib, self); - if (thread == NULL) - e = EINVAL; - else if (thread == self) - e = EDEADLK; - else if (thread->flags & THREAD_DETACHED) - e = EINVAL; - else if ((e = _sem_wait(&thread->donesem, 0, NULL, - &self->delayed_cancel)) == 0) { - if (retval) - *retval = thread->retval; - - /* - * We should be the last having a ref to this thread, - * but someone stupid or evil might haved detached it; - * in that case the thread will clean up itself - */ - if ((thread->flags & THREAD_DETACHED) == 0) - _rthread_free(thread); - } - - LEAVE_CANCEL_POINT_INNER(tib, e); - _rthread_reaper(); - return (e); -} - -int -pthread_detach(pthread_t thread) -{ - int rc = 0; - - _spinlock(&thread->flags_lock); - if (thread->flags & THREAD_DETACHED) { - rc = EINVAL; - _spinunlock(&thread->flags_lock); - } else if (thread->flags & THREAD_DONE) { - _spinunlock(&thread->flags_lock); - _rthread_free(thread); - } else { - thread->flags |= THREAD_DETACHED; - _spinunlock(&thread->flags_lock); - } - _rthread_reaper(); - return (rc); -} - -int -pthread_create(pthread_t *threadp, const pthread_attr_t *attr, - void *(*start_routine)(void *), void *arg) -{ - extern int __isthreaded; - struct tib *tib; - pthread_t thread; - struct __tfork param; - int rc; - - if (!_threads_ready) - _rthread_init(); - - _rthread_reaper(); - - tib = _dl_allocate_tib(sizeof(*thread)); - if (tib == NULL) - return (ENOMEM); - thread = tib->tib_thread; - memset(thread, 0, sizeof(*thread)); - thread->tib = tib; - thread->donesem.lock = _SPINLOCK_UNLOCKED; - thread->flags_lock = _SPINLOCK_UNLOCKED; - thread->fn = start_routine; - thread->arg = arg; - tib->tib_tid = -1; - - thread->attr = attr != NULL ? *(*attr) : _rthread_attr_default; - if (thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) { - pthread_t self = pthread_self(); - - thread->attr.sched_policy = self->attr.sched_policy; - thread->attr.sched_param = self->attr.sched_param; - } - if (thread->attr.detach_state == PTHREAD_CREATE_DETACHED) - thread->flags |= THREAD_DETACHED; - - thread->stack = _rthread_alloc_stack(thread); - if (!thread->stack) { - rc = errno; - goto fail1; - } - - param.tf_tcb = TIB_TO_TCB(tib); - param.tf_tid = &tib->tib_tid; - param.tf_stack = thread->stack->sp; - - _spinlock(&_thread_lock); - LIST_INSERT_HEAD(&_thread_list, thread, threads); - _spinunlock(&_thread_lock); - - /* we're going to be multi-threaded real soon now */ - __isthreaded = 1; - rc = __tfork_thread(¶m, sizeof(param), _rthread_start, thread); - if (rc != -1) { - /* success */ - *threadp = thread; - return (0); - } - - rc = errno; - - _spinlock(&_thread_lock); - LIST_REMOVE(thread, threads); - _spinunlock(&_thread_lock); - _rthread_free_stack(thread->stack); -fail1: - _dl_free_tib(tib, sizeof(*thread)); - - return (rc); -} - -int -pthread_kill(pthread_t thread, int sig) -{ - struct tib *tib = thread->tib; - - if (sig == SIGTHR) - return (EINVAL); - if (thrkill(tib->tib_tid, sig, TIB_TO_TCB(tib))) - return (errno); - return (0); -} - -int pthread_equal(pthread_t t1, pthread_t t2) { return (t1 == t2); } -int -pthread_cancel(pthread_t thread) -{ - struct tib *tib = thread->tib; - pid_t tid = tib->tib_tid; - - if (tib->tib_canceled == 0 && tid != 0 && - (tib->tib_cantcancel & CANCEL_DYING) == 0) { - tib->tib_canceled = 1; - - if ((tib->tib_cantcancel & CANCEL_DISABLED) == 0) { - thrkill(tid, SIGTHR, TIB_TO_TCB(tib)); - return (0); - } - } - return (0); -} - -void -pthread_testcancel(void) -{ - struct tib *tib = TIB_GET(); - - if (tib->tib_canceled && (tib->tib_cantcancel & CANCEL_DISABLED) == 0) - pthread_exit(PTHREAD_CANCELED); -} - -int -pthread_setcancelstate(int state, int *oldstatep) -{ - struct tib *tib = TIB_GET(); - int oldstate; - - oldstate = tib->tib_cantcancel & CANCEL_DISABLED ? - PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE; - if (state == PTHREAD_CANCEL_ENABLE) { - tib->tib_cantcancel &= ~CANCEL_DISABLED; - } else if (state == PTHREAD_CANCEL_DISABLE) { - tib->tib_cantcancel |= CANCEL_DISABLED; - } else { - return (EINVAL); - } - if (oldstatep) - *oldstatep = oldstate; - - return (0); -} -DEF_STRONG(pthread_setcancelstate); - -int -pthread_setcanceltype(int type, int *oldtypep) -{ - struct tib *tib = TIB_GET(); - int oldtype; - - oldtype = tib->tib_thread_flags & TIB_THREAD_ASYNC_CANCEL ? - PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED; - if (type == PTHREAD_CANCEL_DEFERRED) { - tib->tib_thread_flags &=~ TIB_THREAD_ASYNC_CANCEL; - } else if (type == PTHREAD_CANCEL_ASYNCHRONOUS) { - tib->tib_thread_flags |= TIB_THREAD_ASYNC_CANCEL; - } else { - return (EINVAL); - } - if (oldtypep) - *oldtypep = oldtype; - - return (0); -} - -void -pthread_cleanup_push(void (*fn)(void *), void *arg) -{ - struct rthread_cleanup_fn *clfn; - pthread_t self = pthread_self(); - - clfn = calloc(1, sizeof(*clfn)); - if (!clfn) - return; - clfn->fn = fn; - clfn->arg = arg; - clfn->next = self->cleanup_fns; - self->cleanup_fns = clfn; -} - -void -pthread_cleanup_pop(int execute) -{ - struct rthread_cleanup_fn *clfn; - pthread_t self = pthread_self(); - - clfn = self->cleanup_fns; - if (clfn) { - self->cleanup_fns = clfn->next; - if (execute) - clfn->fn(clfn->arg); - free(clfn); - } -} - -int -pthread_getconcurrency(void) -{ - return (concurrency_level); -} - -int -pthread_setconcurrency(int new_level) -{ - if (new_level < 0) - return (EINVAL); - concurrency_level = new_level; - return (0); -} - -/* - * compat debug stuff - */ -void -_thread_dump_info(void) -{ - pthread_t thread; - - _spinlock(&_thread_lock); - LIST_FOREACH(thread, &_thread_list, threads) - printf("thread %d flags 0x%x name %s\n", thread->tib->tib_tid, - thread->tib->tib_thread_flags, thread->name); - _spinunlock(&_thread_lock); -} - -#ifndef NO_PIC -/* - * _rthread_dl_lock() provides the locking for dlopen(), dlclose(), and - * the function called via atexit() to invoke all destructors. The latter - * two call shared-object destructors, which may need to call dlclose(), - * so this lock needs to permit recursive locking. - * The specific code here was extracted from _rthread_mutex_lock() and - * pthread_mutex_unlock() and simplified to use the static variables. - */ -void -_rthread_dl_lock(int what) -{ - static _atomic_lock_t lock = _SPINLOCK_UNLOCKED; - static pthread_t owner = NULL; - static struct pthread_queue lockers = TAILQ_HEAD_INITIALIZER(lockers); - static int count = 0; - - if (what == 0) { - pthread_t self = pthread_self(); - - /* lock, possibly recursive */ - _spinlock(&lock); - if (owner == NULL) { - owner = self; - } else if (owner != self) { - TAILQ_INSERT_TAIL(&lockers, self, waiting); - while (owner != self) { - __thrsleep(self, 0, NULL, &lock, NULL); - _spinlock(&lock); - } - } - count++; - _spinunlock(&lock); - } else if (what == 1) { - /* unlock, possibly recursive */ - if (--count == 0) { - pthread_t next; - - _spinlock(&lock); - owner = next = TAILQ_FIRST(&lockers); - if (next != NULL) - TAILQ_REMOVE(&lockers, next, waiting); - _spinunlock(&lock); - if (next != NULL) - __thrwakeup(next, 1); - } - } else { - /* reinit: used in child after fork to clear the queue */ - lock = _SPINLOCK_UNLOCKED; - if (--count == 0) - owner = NULL; - TAILQ_INIT(&lockers); - } -} -#endif diff --git a/lib/libc/thread/rthread.h b/lib/libc/thread/rthread.h index 4bae5fd4e1d..fa603c1a792 100644 --- a/lib/libc/thread/rthread.h +++ b/lib/libc/thread/rthread.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread.h,v 1.1 2017/08/15 06:13:24 guenther Exp $ */ +/* $OpenBSD: rthread.h,v 1.2 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * All Rights Reserved. @@ -15,222 +15,27 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * Private data structures that back up the typedefs in pthread.h. - * Since only the thread library cares about their size or arrangement, - * it should be possible to switch libraries without relinking. - * - * Do not reorder _atomic_lock_t and sem_t variables in the structs. - * This is due to alignment requirements of certain arches like hppa. - * The current requirement is 16 bytes. - * - * THE MACHINE DEPENDENT CERROR CODE HAS HARD CODED OFFSETS INTO PTHREAD_T! - */ - -#include <sys/queue.h> -#include <semaphore.h> -#include <machine/spinlock.h> - -#ifdef __LP64__ -#define RTHREAD_STACK_SIZE_DEF (512 * 1024) -#else -#define RTHREAD_STACK_SIZE_DEF (256 * 1024) -#endif - -#define _SPINLOCK_UNLOCKED _ATOMIC_LOCK_UNLOCKED - -struct stack { - SLIST_ENTRY(stack) link; /* link for free default stacks */ - void *sp; /* machine stack pointer */ - void *base; /* bottom of allocated area */ - size_t guardsize; /* size of PROT_NONE zone or */ - /* ==1 if application alloced */ - size_t len; /* total size of allocated stack */ -}; - -struct __sem { - _atomic_lock_t lock; - volatile int waitcount; - volatile int value; - int shared; -}; - -TAILQ_HEAD(pthread_queue, pthread); - -#ifdef FUTEX - -struct pthread_mutex { - volatile unsigned int lock; - int type; - pthread_t owner; - int count; - int prioceiling; -}; - -struct pthread_cond { - volatile unsigned int seq; - clockid_t clock; - struct pthread_mutex *mutex; -}; - -#else - -struct pthread_mutex { - _atomic_lock_t lock; - struct pthread_queue lockers; - int type; - pthread_t owner; - int count; - int prioceiling; -}; - -struct pthread_cond { - _atomic_lock_t lock; - struct pthread_queue waiters; - struct pthread_mutex *mutex; - clockid_t clock; -}; -#endif /* FUTEX */ - -struct pthread_mutex_attr { - int ma_type; - int ma_protocol; - int ma_prioceiling; -}; -struct pthread_cond_attr { - clockid_t ca_clock; -}; +#ifndef _RTHREAD_H_ +#define _RTHREAD_H_ -struct pthread_rwlock { - _atomic_lock_t lock; - pthread_t owner; - struct pthread_queue writers; - int readers; -}; - -struct pthread_rwlockattr { - int pshared; -}; - -struct pthread_attr { - void *stack_addr; - size_t stack_size; - size_t guard_size; - int detach_state; - int contention_scope; - int sched_policy; - struct sched_param sched_param; - int sched_inherit; -}; - -#define PTHREAD_MIN_PRIORITY 0 -#define PTHREAD_MAX_PRIORITY 31 - -struct rthread_key { - int used; - void (*destructor)(void *); -}; - -struct rthread_storage { - int keyid; - struct rthread_storage *next; - void *data; -}; - -struct rthread_cleanup_fn { - void (*fn)(void *); - void *arg; - struct rthread_cleanup_fn *next; -}; - -struct pthread_barrier { - pthread_mutex_t mutex; - pthread_cond_t cond; - int threshold; - int in; - int out; - int generation; -}; - -struct pthread_barrierattr { - int pshared; -}; - -struct pthread_spinlock { - _atomic_lock_t lock; - pthread_t owner; -}; - -struct tib; -struct pthread { - struct __sem donesem; - unsigned int flags; - _atomic_lock_t flags_lock; - struct tib *tib; - void *retval; - void *(*fn)(void *); - void *arg; - char name[32]; - struct stack *stack; - LIST_ENTRY(pthread) threads; - TAILQ_ENTRY(pthread) waiting; - pthread_cond_t blocking_cond; - struct pthread_attr attr; - struct rthread_storage *local_storage; - struct rthread_cleanup_fn *cleanup_fns; - int myerrno; - - /* cancel received in a delayed cancel block? */ - int delayed_cancel; -}; -/* flags in pthread->flags */ -#define THREAD_DONE 0x001 -#define THREAD_DETACHED 0x002 - -/* flags in tib->tib_thread_flags */ -#define TIB_THREAD_ASYNC_CANCEL 0x001 -#define TIB_THREAD_INITIAL_STACK 0x002 /* has stack from exec */ - -#define ENTER_DELAYED_CANCEL_POINT(tib, self) \ - (self)->delayed_cancel = 0; \ - ENTER_CANCEL_POINT_INNER(tib, 1, 1) - -#define ROUND_TO_PAGE(size) \ - (((size) + (_thread_pagesize - 1)) & ~(_thread_pagesize - 1)) +#include "thread_private.h" __BEGIN_HIDDEN_DECLS -void _spinlock(volatile _atomic_lock_t *); -int _spinlocktry(volatile _atomic_lock_t *); -void _spinunlock(volatile _atomic_lock_t *); -int _sem_wait(sem_t, int, const struct timespec *, int *); -int _sem_post(sem_t); - -void _rthread_init(void); -struct stack *_rthread_alloc_stack(pthread_t); -void _rthread_free_stack(struct stack *); void _rthread_tls_destructors(pthread_t); -void _rthread_debug(int, const char *, ...) - __attribute__((__format__ (printf, 2, 3))); -void _rthread_debug_init(void); -#ifndef NO_PIC -void _rthread_dl_lock(int what); -#endif -void _thread_malloc_reinit(void); -extern int _threads_ready; -extern size_t _thread_pagesize; -extern LIST_HEAD(listhead, pthread) _thread_list; -extern _atomic_lock_t _thread_lock; -extern struct pthread_attr _rthread_attr_default; +extern int _rthread_debug_level; +extern struct pthread _initial_thread; __END_HIDDEN_DECLS -void _thread_dump_info(void); +PROTO_NORMAL(__threxit); +PROTO_NORMAL(__thrsigdivert); +PROTO_NORMAL(__thrsleep); +PROTO_NORMAL(__thrwakeup); + +PROTO_NORMAL(_spinlock); +PROTO_STD_DEPRECATED(_spinlocktry); +PROTO_NORMAL(_spinunlock); +PROTO_NORMAL(_rthread_debug); -/* syscalls not declared in system headers */ -#define REDIRECT_SYSCALL(x) typeof(x) x asm("_thread_sys_"#x) -void __threxit(pid_t *); -int __thrsleep(const volatile void *, clockid_t, const struct timespec *, - volatile void *, const int *); -int __thrwakeup(const volatile void *, int n); -int __thrsigdivert(sigset_t, siginfo_t *, const struct timespec *); +#endif /* _RTHREAD_H_ */ diff --git a/lib/libc/thread/rthread_cb.h b/lib/libc/thread/rthread_cb.h index 4865e2ec4a2..3e8604c4ed4 100644 --- a/lib/libc/thread/rthread_cb.h +++ b/lib/libc/thread/rthread_cb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_cb.h,v 1.1 2017/08/15 06:13:24 guenther Exp $ */ +/* $OpenBSD: rthread_cb.h,v 1.2 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2016 Philip Guenther <guenther@openbsd.org> * All Rights Reserved. @@ -19,8 +19,6 @@ #include <stdio.h> __BEGIN_HIDDEN_DECLS -pid_t _thread_fork(void); -pid_t _thread_vfork(void); void _thread_flockfile(FILE *); int _thread_ftrylockfile(FILE *); void _thread_funlockfile(FILE *); diff --git a/lib/libc/thread/rthread_cond.c b/lib/libc/thread/rthread_cond.c index fb69dd2cb0a..3fd9bfcd56e 100644 --- a/lib/libc/thread/rthread_cond.c +++ b/lib/libc/thread/rthread_cond.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_cond.c,v 1.3 2017/08/15 07:06:29 guenther Exp $ */ +/* $OpenBSD: rthread_cond.c,v 1.4 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org> * Copyright (c) 2012 Philip Guenther <guenther@openbsd.org> @@ -68,7 +68,6 @@ pthread_cond_destroy(pthread_cond_t *condp) return (0); } -DEF_STRONG(pthread_cond_destroy); int _rthread_cond_timedwait(pthread_cond_t cond, pthread_mutex_t *mutexp, @@ -166,7 +165,6 @@ pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp) cond = *condp; return (_rthread_cond_timedwait(cond, mutexp, NULL)); } -DEF_STRONG(pthread_cond_wait); int pthread_cond_signal(pthread_cond_t *condp) @@ -187,7 +185,6 @@ pthread_cond_signal(pthread_cond_t *condp) return (0); } -DEF_STRONG(pthread_cond_signal); int pthread_cond_broadcast(pthread_cond_t *condp) @@ -212,4 +209,3 @@ pthread_cond_broadcast(pthread_cond_t *condp) return (0); } -DEF_STRONG(pthread_cond_broadcast); diff --git a/lib/libc/thread/rthread_condattr.c b/lib/libc/thread/rthread_condattr.c index 3a5d8772b05..be3efc33e6a 100644 --- a/lib/libc/thread/rthread_condattr.c +++ b/lib/libc/thread/rthread_condattr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_condattr.c,v 1.2 2017/08/15 06:38:41 guenther Exp $ */ +/* $OpenBSD: rthread_condattr.c,v 1.3 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * Copyright (c) 2012 Philip Guenther <guenther@openbsd.org> @@ -20,12 +20,9 @@ * Condition Variable Attributes */ -#include <assert.h> #include <errno.h> #include <pthread.h> #include <stdlib.h> -#include <string.h> -#include <unistd.h> #include "rthread.h" diff --git a/lib/libc/thread/rthread_debug.c b/lib/libc/thread/rthread_debug.c index 18d3a8567d6..67dca29e054 100644 --- a/lib/libc/thread/rthread_debug.c +++ b/lib/libc/thread/rthread_debug.c @@ -1,27 +1,14 @@ -/* $OpenBSD: rthread_debug.c,v 1.2 2017/08/15 06:38:41 guenther Exp $ */ +/* $OpenBSD: rthread_debug.c,v 1.3 2017/09/05 02:40:54 guenther Exp $ */ /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ #include <pthread.h> #include <stdarg.h> #include <stdio.h> -#include <stdlib.h> #include <unistd.h> #include "rthread.h" -REDIRECT_SYSCALL(issetugid); - -int _rthread_debug_level; - -/* - * Note: messages truncated at 255 characters. Could use vasprintf, - * but don't want to use malloc here so the function can be used - * in signal handlers. - */ -#define MAX_MSG_LEN 256 -#define RTHREAD_ENV_DEBUG "RTHREAD_DEBUG" - /* * format and send output to stderr if the given "level" is less than or * equal to the current debug level. Messages with a level <= 0 will @@ -30,47 +17,12 @@ int _rthread_debug_level; void _rthread_debug(int level, const char *fmt, ...) { - char msg[MAX_MSG_LEN]; - char *p; - int cnt; - ssize_t c; - if (_rthread_debug_level >= level) { va_list ap; va_start(ap, fmt); - cnt = vsnprintf(msg, MAX_MSG_LEN, fmt, ap); + vdprintf(STDERR_FILENO, fmt, ap); va_end(ap); - if (cnt > MAX_MSG_LEN - 1) - cnt = MAX_MSG_LEN - 1; - p = msg; - do { - c = write(STDERR_FILENO, p, cnt); - if (c == -1) - break; - if (c != cnt) - sched_yield(); - p += c; - cnt -= c; - } while (cnt > 0); } } +DEF_STRONG(_rthread_debug); -/* - * set the debug level from an environment string. Bogus values are - * silently ignored. - */ -void -_rthread_debug_init(void) -{ - char *envp; - char *rem; - - if (issetugid()) - return; - envp = getenv(RTHREAD_ENV_DEBUG); - if (envp) { - _rthread_debug_level = (int) strtol(envp, &rem, 0); - if (*rem || _rthread_debug_level < 0) - _rthread_debug_level = 0; - } -} diff --git a/lib/libc/thread/rthread_libc.c b/lib/libc/thread/rthread_libc.c index 406fc9f939e..b3fcf22cad5 100644 --- a/lib/libc/thread/rthread_libc.c +++ b/lib/libc/thread/rthread_libc.c @@ -1,15 +1,11 @@ -/* $OpenBSD: rthread_libc.c,v 1.1 2017/08/15 06:13:24 guenther Exp $ */ +/* $OpenBSD: rthread_libc.c,v 1.2 2017/09/05 02:40:54 guenther Exp $ */ /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ -#include <sys/time.h> - #include <pthread.h> #include <stdlib.h> #include <string.h> -#include "thread_private.h" /* in libc/include */ - #include "rthread.h" #include "rthread_cb.h" @@ -195,7 +191,7 @@ _thread_malloc_unlock(int i) pthread_mutex_unlock(&malloc_mutex[i]); } -void +static void _thread_malloc_reinit(void) { int i; @@ -260,3 +256,28 @@ _thread_arc4_unlock(void) { _spinunlock(&arc4_lock); } + +pid_t +_thread_dofork(pid_t (*sys_fork)(void)) +{ + int i; + pid_t newid; + + _thread_atexit_lock(); + for (i = 0; i < _MALLOC_MUTEXES; i++) + _thread_malloc_lock(i); + _thread_arc4_lock(); + + newid = sys_fork(); + + _thread_arc4_unlock(); + if (newid == 0) + _thread_malloc_reinit(); + else + for (i = 0; i < _MALLOC_MUTEXES; i++) + _thread_malloc_unlock(i); + _thread_atexit_unlock(); + + return newid; +} + diff --git a/lib/libc/thread/rthread_sync.c b/lib/libc/thread/rthread_sync.c index 6f6bda4e6a4..91ce55cbcf9 100644 --- a/lib/libc/thread/rthread_sync.c +++ b/lib/libc/thread/rthread_sync.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_sync.c,v 1.3 2017/08/15 07:06:29 guenther Exp $ */ +/* $OpenBSD: rthread_sync.c,v 1.4 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * Copyright (c) 2012 Philip Guenther <guenther@openbsd.org> @@ -280,7 +280,6 @@ pthread_cond_destroy(pthread_cond_t *condp) return (0); } -DEF_STRONG(pthread_cond_destroy); int pthread_cond_timedwait(pthread_cond_t *condp, pthread_mutex_t *mutexp, @@ -573,7 +572,6 @@ pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp) return (0); } -DEF_STRONG(pthread_cond_wait); int @@ -623,7 +621,6 @@ pthread_cond_signal(pthread_cond_t *condp) return (0); } -DEF_STRONG(pthread_cond_signal); int pthread_cond_broadcast(pthread_cond_t *condp) @@ -689,4 +686,3 @@ pthread_cond_broadcast(pthread_cond_t *condp) return (0); } -DEF_STRONG(pthread_cond_broadcast); diff --git a/lib/libc/thread/rthread_tls.c b/lib/libc/thread/rthread_tls.c index ba92ca1ff30..58b39bb7df7 100644 --- a/lib/libc/thread/rthread_tls.c +++ b/lib/libc/thread/rthread_tls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_tls.c,v 1.3 2017/08/15 07:06:29 guenther Exp $ */ +/* $OpenBSD: rthread_tls.c,v 1.4 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * All Rights Reserved. @@ -23,8 +23,17 @@ #include <pthread.h> #include <stdlib.h> +#include <pthread.h> +#include <stdlib.h> + #include "rthread.h" + +struct rthread_key { + int used; + void (*destructor)(void *); +}; + static struct rthread_key rkeys[PTHREAD_KEYS_MAX]; static _atomic_lock_t rkeyslock = _SPINLOCK_UNLOCKED; @@ -61,7 +70,6 @@ DEF_STRONG(pthread_key_create); int pthread_key_delete(pthread_key_t key) { - pthread_t thread; struct rthread_storage *rs; int rv = 0; @@ -76,14 +84,14 @@ pthread_key_delete(pthread_key_t key) rkeys[key].used = 0; rkeys[key].destructor = NULL; - _spinlock(&_thread_lock); - LIST_FOREACH(thread, &_thread_list, threads) { - for (rs = thread->local_storage; rs; rs = rs->next) { + if (_thread_cb.tc_thread_key_zero != NULL) + _thread_cb.tc_thread_key_zero(key); + else { + for (rs = _initial_thread.local_storage; rs; rs = rs->next) { if (rs->keyid == key) rs->data = NULL; } } - _spinunlock(&_thread_lock); out: _spinunlock(&rkeyslock); diff --git a/lib/libc/thread/synch.h b/lib/libc/thread/synch.h index 0ac8b3419b1..8ab379530e8 100644 --- a/lib/libc/thread/synch.h +++ b/lib/libc/thread/synch.h @@ -1,4 +1,4 @@ -/* $OpenBSD: synch.h,v 1.1 2017/08/15 06:13:24 guenther Exp $ */ +/* $OpenBSD: synch.h,v 1.2 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2017 Martin Pieuchot * @@ -19,8 +19,6 @@ #include <sys/time.h> #include <sys/futex.h> -REDIRECT_SYSCALL(futex); - static inline int _wake(volatile uint32_t *p, int n) { diff --git a/lib/librthread/Makefile b/lib/librthread/Makefile index 5f44aff5958..78f706087fc 100644 --- a/lib/librthread/Makefile +++ b/lib/librthread/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.47 2017/07/04 14:33:43 visa Exp $ +# $OpenBSD: Makefile,v 1.48 2017/09/05 02:40:54 guenther Exp $ LIB=pthread LIBCSRCDIR= ${.CURDIR}/../libc @@ -22,16 +22,11 @@ SRCS= rthread.c \ rthread_attr.c \ rthread_barrier.c \ rthread_barrier_attr.c \ - rthread_condattr.c \ - rthread_debug.c \ - rthread_file.c \ rthread_fork.c \ rthread_getcpuclockid.c \ - rthread_libc.c \ rthread_mutex_prio.c \ rthread_mutexattr.c \ rthread_np.c \ - rthread_once.c \ rthread_rwlock.c \ rthread_rwlockattr.c \ rthread_sched.c \ @@ -39,20 +34,8 @@ SRCS= rthread.c \ rthread_sig.c \ rthread_stack.c \ rthread_spin_lock.c \ - rthread_tls.c \ sched_prio.c -.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" || \ - ${MACHINE_ARCH} == "mips64" || ${MACHINE_ARCH} == "mips64el" -CFLAGS+= -DFUTEX -SRCS+= rthread_mutex.c \ - rthread_cond.c -.else -SRCS+= rthread_sync.c -.endif - -OBJS+= _atomic_lock.o - SRCDIR= ${.CURDIR}/../libpthread .include "${SRCDIR}/include/Makefile.inc" .include "${SRCDIR}/man/Makefile.inc" diff --git a/lib/librthread/Symbols.map b/lib/librthread/Symbols.map index 784b887cd01..a7aa4ce407d 100644 --- a/lib/librthread/Symbols.map +++ b/lib/librthread/Symbols.map @@ -1,14 +1,5 @@ { global: - /* symbols that no one should be using currently */ - _init; - _fini; - __data_start; - __bss_start; - _edata; - _end; - __end; - /* pthread implementation */ pthread_attr_destroy; pthread_attr_getdetachstate; @@ -40,38 +31,17 @@ pthread_cancel; pthread_cleanup_pop; pthread_cleanup_push; - pthread_cond_broadcast; - pthread_cond_destroy; - pthread_cond_init; - pthread_cond_signal; - pthread_cond_timedwait; - pthread_cond_wait; - pthread_condattr_destroy; - pthread_condattr_getclock; - pthread_condattr_init; - pthread_condattr_setclock; pthread_create; pthread_detach; - pthread_equal; - pthread_exit; pthread_getconcurrency; pthread_getcpuclockid; pthread_getprio; pthread_getschedparam; - pthread_getspecific; pthread_join; - pthread_key_create; - pthread_key_delete; pthread_kill; pthread_main_np; - pthread_mutex_destroy; pthread_mutex_getprioceiling; - pthread_mutex_init; - pthread_mutex_lock; pthread_mutex_setprioceiling; - pthread_mutex_timedlock; - pthread_mutex_trylock; - pthread_mutex_unlock; pthread_mutexattr_destroy; pthread_mutexattr_getkind_np; pthread_mutexattr_getprioceiling; @@ -82,7 +52,6 @@ pthread_mutexattr_setprioceiling; pthread_mutexattr_setprotocol; pthread_mutexattr_settype; - pthread_once; pthread_rwlock_destroy; pthread_rwlock_init; pthread_rwlock_rdlock; @@ -96,14 +65,12 @@ pthread_rwlockattr_getpshared; pthread_rwlockattr_init; pthread_rwlockattr_setpshared; - pthread_self; pthread_set_name_np; pthread_setcancelstate; pthread_setcanceltype; pthread_setconcurrency; pthread_setprio; pthread_setschedparam; - pthread_setspecific; pthread_spin_destroy; pthread_spin_init; pthread_spin_lock; @@ -129,9 +96,6 @@ /* used for debugging & regress */ _thread_dump_info; - /* other overrides of libc */ - _atomic_lock; - _dlctl; local: *; diff --git a/lib/librthread/arch/aarch64/_atomic_lock.c b/lib/librthread/arch/aarch64/_atomic_lock.c deleted file mode 100644 index 30f10a1e10d..00000000000 --- a/lib/librthread/arch/aarch64/_atomic_lock.c +++ /dev/null @@ -1,49 +0,0 @@ -/* $OpenBSD: _atomic_lock.c,v 1.1 2017/01/11 13:45:59 patrick Exp $ */ - -/* - * Copyright (c) 2004 Dale Rahn. 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. - * - * 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. - */ - -/* - * Atomic lock for arm - */ - -#include <sys/types.h> -#include <machine/spinlock.h> - -int -_atomic_lock(volatile _atomic_lock_t *lock) -{ - _atomic_lock_t old = 0; - uint32_t scratch = 0; - - __asm__("1: ldaxr %w0, [%x1] \n" - " stlxr %w2, %w3, [%x1] \n" - " cmp %w2, #0 \n" - " bne 1b \n" - " dmb sy \n" - : "+r" (old), "+r" (lock), "+r" (scratch) - : "r" (_ATOMIC_LOCK_LOCKED)); - - return (old != _ATOMIC_LOCK_UNLOCKED); -} diff --git a/lib/librthread/arch/alpha/_atomic_lock.S b/lib/librthread/arch/alpha/_atomic_lock.S deleted file mode 100644 index af482bcd004..00000000000 --- a/lib/librthread/arch/alpha/_atomic_lock.S +++ /dev/null @@ -1,19 +0,0 @@ -/* $OpenBSD: _atomic_lock.S,v 1.3 2013/06/04 17:55:51 miod Exp $ */ -/* David Leonard, <d@csee.uq.edu.au>. Public domain. */ - -#include <machine/asm.h> - -LEAF(_atomic_lock,1) - LDGP(pv) - - /* NOTE: using ldl_l/stl_c instead of - ldq_l and stq_c as machine/spinlock.h - defines _atomic_lock_t as int */ -0: ldl_l v0, 0(a0) /* read existing lock value */ - mov 1, t0 /* locked value to store */ - stl_c t0, 0(a0) /* attempt to store, status in t0 */ - beq t0, 1f /* branch forward to optimise prediction */ - mb /* sync with other processors */ - RET /* return with v0==0 if lock obtained */ -1: br 0b /* loop to try again */ -END(_atomic_lock) diff --git a/lib/librthread/arch/amd64/_atomic_lock.c b/lib/librthread/arch/amd64/_atomic_lock.c deleted file mode 100644 index f3527aaf081..00000000000 --- a/lib/librthread/arch/amd64/_atomic_lock.c +++ /dev/null @@ -1,26 +0,0 @@ -/* $OpenBSD: _atomic_lock.c,v 1.4 2013/06/01 20:47:40 tedu Exp $ */ - -/* David Leonard, <d@csee.uq.edu.au>. Public domain. */ - -/* - * Atomic lock for amd64 -- taken from i386 code. - */ - -#include <machine/spinlock.h> - -int -_atomic_lock(volatile _atomic_lock_t *lock) -{ - _atomic_lock_t old; - - /* - * Use the eXCHanGe instruction to swap the lock value with - * a local variable containing the locked state. - */ - old = _ATOMIC_LOCK_LOCKED; - __asm__("xchg %0,(%2)" - : "=r" (old) - : "0" (old), "r" (lock)); - - return (old != _ATOMIC_LOCK_UNLOCKED); -} diff --git a/lib/librthread/arch/arm/_atomic_lock.c b/lib/librthread/arch/arm/_atomic_lock.c deleted file mode 100644 index cae72df40b8..00000000000 --- a/lib/librthread/arch/arm/_atomic_lock.c +++ /dev/null @@ -1,49 +0,0 @@ -/* $OpenBSD: _atomic_lock.c,v 1.8 2017/01/05 16:52:42 patrick Exp $ */ - -/* - * Copyright (c) 2004 Dale Rahn. 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. - * - * 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. - */ - -/* - * Atomic lock for arm - */ - -#include <sys/types.h> -#include <machine/spinlock.h> - -int -_atomic_lock(volatile _atomic_lock_t *lock) -{ - _atomic_lock_t old = 0; - uint32_t scratch = 0; - - __asm__("1: ldrex %0, [%1] \n" - " strex %2, %3, [%1] \n" - " cmp %2, #0 \n" - " bne 1b \n" - " dmb sy \n" - : "+r" (old), "+r" (lock), "+r" (scratch) - : "r" (_ATOMIC_LOCK_LOCKED)); - - return (old != _ATOMIC_LOCK_UNLOCKED); -} diff --git a/lib/librthread/arch/hppa/_atomic_lock.c b/lib/librthread/arch/hppa/_atomic_lock.c deleted file mode 100644 index cdde57c2a0e..00000000000 --- a/lib/librthread/arch/hppa/_atomic_lock.c +++ /dev/null @@ -1,41 +0,0 @@ -/* $OpenBSD: _atomic_lock.c,v 1.7 2013/06/01 20:47:40 tedu Exp $ */ -/* - * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <machine/spinlock.h> -#ifdef DIAGNOSTIC -#include <stdio.h> -#include <stdlib.h> -#endif - -int -_atomic_lock(volatile _atomic_lock_t *lock) -{ - volatile _atomic_lock_t old; - -#ifdef DIAGNOSTIC - if ((unsigned long)lock & 0xf) { - printf("lock not 16 byte aligned\n"); - abort(); - } -#endif - - asm volatile ("ldcws 0(%2),%0" - : "=&r" (old), "+m" (lock) - : "r" (lock)); - - return (old == _ATOMIC_LOCK_LOCKED); -} diff --git a/lib/librthread/arch/i386/_atomic_lock.c b/lib/librthread/arch/i386/_atomic_lock.c deleted file mode 100644 index b765644fb82..00000000000 --- a/lib/librthread/arch/i386/_atomic_lock.c +++ /dev/null @@ -1,25 +0,0 @@ -/* $OpenBSD: _atomic_lock.c,v 1.4 2013/06/01 20:47:40 tedu Exp $ */ -/* David Leonard, <d@csee.uq.edu.au>. Public domain. */ - -/* - * Atomic lock for i386 - */ - -#include <machine/spinlock.h> - -int -_atomic_lock(volatile _atomic_lock_t *lock) -{ - _atomic_lock_t old; - - /* - * Use the eXCHanGe instruction to swap the lock value with - * a local variable containing the locked state. - */ - old = _ATOMIC_LOCK_LOCKED; - __asm__("xchg %0,(%2)" - : "=r" (old) - : "0" (old), "r" (lock)); - - return (old != _ATOMIC_LOCK_UNLOCKED); -} diff --git a/lib/librthread/arch/m88k/_atomic_lock.c b/lib/librthread/arch/m88k/_atomic_lock.c deleted file mode 100644 index ee638327d79..00000000000 --- a/lib/librthread/arch/m88k/_atomic_lock.c +++ /dev/null @@ -1,44 +0,0 @@ -/* $OpenBSD: _atomic_lock.c,v 1.5 2014/04/18 15:09:52 guenther Exp $ */ - -/* - * Copyright (c) 2003, Miodrag Vallat. - * - * 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. - * - * 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. - */ - -/* - * Atomic lock for m88k - */ - -#include <machine/spinlock.h> - -int -_atomic_lock(volatile _atomic_lock_t *lock) -{ - _atomic_lock_t old; - - old = _ATOMIC_LOCK_LOCKED; - __asm__ volatile - ("xmem %0, %2, %%r0" : "=r" (old) : "0" (old), "r" (lock)); - - return (old != _ATOMIC_LOCK_UNLOCKED); -} diff --git a/lib/librthread/arch/mips64/_atomic_lock.c b/lib/librthread/arch/mips64/_atomic_lock.c deleted file mode 100644 index 4b33cb39ac9..00000000000 --- a/lib/librthread/arch/mips64/_atomic_lock.c +++ /dev/null @@ -1,27 +0,0 @@ -/* $OpenBSD: _atomic_lock.c,v 1.8 2014/04/18 15:09:52 guenther Exp $ */ - -/* - * Atomic lock for mips - * Written by Miodrag Vallat <miod@openbsd.org> - placed in the public domain. - */ - -#include <machine/spinlock.h> - -int -_atomic_lock(volatile _atomic_lock_t *lock) -{ - _atomic_lock_t old; - - __asm__ volatile ( - ".set noreorder\n" - "1: ll %0, 0(%1)\n" - " sc %2, 0(%1)\n" - " beqz %2, 1b\n" - " addi %2, $0, %3\n" - ".set reorder\n" - : "=&r"(old) - : "r"(lock), "r"(_ATOMIC_LOCK_LOCKED), "i"(_ATOMIC_LOCK_LOCKED) - : "memory"); - - return (old != _ATOMIC_LOCK_UNLOCKED); -} diff --git a/lib/librthread/arch/powerpc/_atomic_lock.c b/lib/librthread/arch/powerpc/_atomic_lock.c deleted file mode 100644 index 705f682114c..00000000000 --- a/lib/librthread/arch/powerpc/_atomic_lock.c +++ /dev/null @@ -1,53 +0,0 @@ -/* $OpenBSD: _atomic_lock.c,v 1.5 2013/06/01 20:47:40 tedu Exp $ */ -/* - * Copyright (c) 1998 Dale Rahn <drahn@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * Atomic lock for powerpc - */ - -#include <machine/spinlock.h> - -int -_atomic_lock(volatile _atomic_lock_t *lock) -{ - _atomic_lock_t old; - - __asm__("1: lwarx 0,0,%1 \n" - " stwcx. %2,0,%1 \n" - " bne- 1b \n" - " mr %0, 0 \n" - : "=r" (old), "=r" (lock) - : "r" (_ATOMIC_LOCK_LOCKED), "1" (lock) : "0" - ); - - return (old != _ATOMIC_LOCK_UNLOCKED); - - /* - * Dale <drahn@openbsd.org> says: - * Side note. to prevent two processes from accessing - * the same address with the lwarx in one instruction - * and the stwcx in another process, the current powerpc - * kernel uses a stwcx instruction without the corresponding - * lwarx which causes any reservation of a process - * to be removed. if a context switch occurs - * between the two accesses the store will not occur - * and the condition code will cause it to loop. If on - * a dual processor machine, the reserve will cause - * appropriate bus cycle accesses to notify other - * processors. - */ -} diff --git a/lib/librthread/arch/sh/_atomic_lock.c b/lib/librthread/arch/sh/_atomic_lock.c deleted file mode 100644 index 4dca89705db..00000000000 --- a/lib/librthread/arch/sh/_atomic_lock.c +++ /dev/null @@ -1,46 +0,0 @@ -/* $OpenBSD: _atomic_lock.c,v 1.3 2013/06/01 20:47:40 tedu Exp $ */ - -/*- - * Copyright (c) 2002 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Gregory McGarry. - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 THE FOUNDATION 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. - */ - -#include <machine/spinlock.h> - -int -_atomic_lock(volatile _atomic_lock_t *lock) -{ - _atomic_lock_t old; - - __asm volatile( - " tas.b %0 \n" - " mov #0, %1 \n" - " rotcl %1 \n" - : "=m" (*lock), "=r" (old)); - - return (old == 0); -} diff --git a/lib/librthread/arch/sparc64/_atomic_lock.c b/lib/librthread/arch/sparc64/_atomic_lock.c deleted file mode 100644 index e18426b848e..00000000000 --- a/lib/librthread/arch/sparc64/_atomic_lock.c +++ /dev/null @@ -1,41 +0,0 @@ -/* $OpenBSD: _atomic_lock.c,v 1.5 2013/06/01 20:47:40 tedu Exp $ */ -/* David Leonard, <d@csee.uq.edu.au>. Public domain. */ - -/* - * Atomic lock for sparc64 - */ - -#include <machine/spinlock.h> - -int -_atomic_lock(volatile _atomic_lock_t * lock) -{ - _atomic_lock_t old; - - /* - * " ldstub [address], reg_rd - * - * The atomic load-store instructions copy a byte from memory - * into r[rd]m then rewrite the addressed byte in memory to all - * ones [_ATOMIC_LOCK_LOCKED]. The operation is performed - * atomically, that is, without allowing intervening interrupts - * or deferred traps. In a multiprocessor system, two or more - * processors executing atomic load-store unsigned byte [...] - * addressing the same byte [...] simultaneously are guaranteed - * to execute them in an undefined, but serial order." - * - p101, The SPARC Architecture Manual (version 8) Prentice-Hall - * - * "LDSTUB loads a byte value from memory to a register and writes - * the value FF_16 into the addressed byte atomically. LDSTUB - * is the classic test-and-set instruction. Like SWAP, it has - * a consensus number of two and so cannot resolve more than - * two contending processes in a wait-free fashion." - * - p129, The SPARC Architecture Manual (version 9) Prentice-Hall - * (See also section J.6 (spinlocks)) - * - * (No change to the condition codes are documented.) - */ - __asm__("ldstub [%1], %0" : "=&r" (old) : "r" (lock) : "memory"); - - return (old == _ATOMIC_LOCK_LOCKED); -} diff --git a/lib/librthread/pthread.h b/lib/librthread/pthread.h index cc656fb8440..d6dba9a485f 100644 --- a/lib/librthread/pthread.h +++ b/lib/librthread/pthread.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pthread.h,v 1.3 2016/04/15 21:06:23 guenther Exp $ */ +/* $OpenBSD: pthread.h,v 1.4 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2016 Philip Guenther <guenther@openbsd.org> * @@ -53,36 +53,17 @@ PROTO_STD_DEPRECATED(pthread_barrierattr_setpshared); PROTO_STD_DEPRECATED(pthread_cancel); PROTO_STD_DEPRECATED(pthread_cleanup_pop); PROTO_STD_DEPRECATED(pthread_cleanup_push); -PROTO_NORMAL(pthread_cond_broadcast); -PROTO_NORMAL(pthread_cond_destroy); -PROTO_NORMAL(pthread_cond_init); -PROTO_NORMAL(pthread_cond_signal); -PROTO_STD_DEPRECATED(pthread_cond_timedwait); -PROTO_NORMAL(pthread_cond_wait); -PROTO_STD_DEPRECATED(pthread_condattr_destroy); PROTO_STD_DEPRECATED(pthread_condattr_getclock); -PROTO_STD_DEPRECATED(pthread_condattr_init); PROTO_STD_DEPRECATED(pthread_condattr_setclock); PROTO_STD_DEPRECATED(pthread_create); PROTO_STD_DEPRECATED(pthread_detach); -PROTO_STD_DEPRECATED(pthread_equal); -PROTO_NORMAL(pthread_exit); PROTO_STD_DEPRECATED(pthread_getconcurrency); PROTO_STD_DEPRECATED(pthread_getcpuclockid); PROTO_STD_DEPRECATED(pthread_getschedparam); -PROTO_NORMAL(pthread_getspecific); PROTO_STD_DEPRECATED(pthread_join); -PROTO_NORMAL(pthread_key_create); -PROTO_STD_DEPRECATED(pthread_key_delete); PROTO_STD_DEPRECATED(pthread_kill); -PROTO_NORMAL(pthread_mutex_destroy); PROTO_STD_DEPRECATED(pthread_mutex_getprioceiling); -PROTO_NORMAL(pthread_mutex_init); -PROTO_NORMAL(pthread_mutex_lock); PROTO_STD_DEPRECATED(pthread_mutex_setprioceiling); -PROTO_STD_DEPRECATED(pthread_mutex_timedlock); -PROTO_STD_DEPRECATED(pthread_mutex_trylock); -PROTO_NORMAL(pthread_mutex_unlock); PROTO_STD_DEPRECATED(pthread_mutexattr_destroy); PROTO_STD_DEPRECATED(pthread_mutexattr_getprioceiling); PROTO_STD_DEPRECATED(pthread_mutexattr_getprotocol); @@ -91,7 +72,6 @@ PROTO_STD_DEPRECATED(pthread_mutexattr_init); PROTO_STD_DEPRECATED(pthread_mutexattr_setprioceiling); PROTO_STD_DEPRECATED(pthread_mutexattr_setprotocol); PROTO_STD_DEPRECATED(pthread_mutexattr_settype); -PROTO_STD_DEPRECATED(pthread_once); PROTO_STD_DEPRECATED(pthread_rwlock_destroy); PROTO_NORMAL(pthread_rwlock_init); PROTO_STD_DEPRECATED(pthread_rwlock_rdlock); @@ -105,12 +85,10 @@ PROTO_STD_DEPRECATED(pthread_rwlockattr_destroy); PROTO_STD_DEPRECATED(pthread_rwlockattr_getpshared); PROTO_STD_DEPRECATED(pthread_rwlockattr_init); PROTO_STD_DEPRECATED(pthread_rwlockattr_setpshared); -PROTO_NORMAL(pthread_self); PROTO_NORMAL(pthread_setcancelstate); PROTO_STD_DEPRECATED(pthread_setcanceltype); PROTO_STD_DEPRECATED(pthread_setconcurrency); PROTO_STD_DEPRECATED(pthread_setschedparam); -PROTO_NORMAL(pthread_setspecific); PROTO_STD_DEPRECATED(pthread_spin_destroy); PROTO_STD_DEPRECATED(pthread_spin_init); PROTO_STD_DEPRECATED(pthread_spin_lock); diff --git a/lib/librthread/rthread.c b/lib/librthread/rthread.c index b9aa60ef77b..c3eec97d2fa 100644 --- a/lib/librthread/rthread.c +++ b/lib/librthread/rthread.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread.c,v 1.95 2017/07/27 16:35:08 tedu Exp $ */ +/* $OpenBSD: rthread.c,v 1.96 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * All Rights Reserved. @@ -38,7 +38,6 @@ #include <pthread.h> #include "cancel.h" /* in libc/include */ -#include "thread_private.h" #include "rthread.h" #include "rthread_cb.h" @@ -87,24 +86,6 @@ struct pthread_attr _rthread_attr_default = { /* * internal support functions */ -void -_spinlock(volatile _atomic_lock_t *lock) -{ - while (_atomic_lock(lock)) - sched_yield(); -} - -int -_spinlocktry(volatile _atomic_lock_t *lock) -{ - return 0 == _atomic_lock(lock); -} - -void -_spinunlock(volatile _atomic_lock_t *lock) -{ - *lock = _ATOMIC_LOCK_UNLOCKED; -} static void _rthread_start(void *v) @@ -169,29 +150,56 @@ multi_threaded_tcb(void) } #endif /* TCB_HAVE_MD_GET */ -void -_thread_canceled(void) +static void +_rthread_free(pthread_t thread) +{ + _spinlock(&_thread_gc_lock); + TAILQ_INSERT_TAIL(&_thread_gc_list, thread, waiting); + _spinunlock(&_thread_gc_lock); +} + +static void +_thread_release(pthread_t thread) +{ + _spinlock(&_thread_lock); + LIST_REMOVE(thread, threads); + _spinunlock(&_thread_lock); + + _spinlock(&thread->flags_lock); + if (thread->flags & THREAD_DETACHED) { + _spinunlock(&thread->flags_lock); + _rthread_free(thread); + } else { + thread->flags |= THREAD_DONE; + _spinunlock(&thread->flags_lock); + _sem_post(&thread->donesem); + } +} + +static void +_thread_key_zero(int key) { - pthread_exit(PTHREAD_CANCELED); + pthread_t thread; + struct rthread_storage *rs; + + LIST_FOREACH(thread, &_thread_list, threads) { + for (rs = thread->local_storage; rs; rs = rs->next) { + if (rs->keyid == key) + rs->data = NULL; + } + } } void _rthread_init(void) { - pthread_t thread = &_initial_thread; - struct tib *tib; + pthread_t thread = pthread_self(); struct sigaction sa; - tib = TIB_GET(); - tib->tib_thread = thread; - thread->tib = tib; + if (_threads_ready) + return; - thread->donesem.lock = _SPINLOCK_UNLOCKED; - tib->tib_thread_flags = TIB_THREAD_INITIAL_STACK; - thread->flags_lock = _SPINLOCK_UNLOCKED; - strlcpy(thread->name, "Main process", sizeof(thread->name)); LIST_INSERT_HEAD(&_thread_list, thread, threads); - _rthread_debug_init(); _thread_pagesize = (size_t)sysconf(_SC_PAGESIZE); _rthread_attr_default.guard_size = _thread_pagesize; @@ -205,26 +213,10 @@ _rthread_init(void) cb.tc_errnoptr = multi_threaded_errnoptr; cb.tc_tcb = multi_threaded_tcb; #endif - cb.tc_canceled = _thread_canceled; - cb.tc_flockfile = _thread_flockfile; - cb.tc_ftrylockfile = _thread_ftrylockfile; - cb.tc_funlockfile = _thread_funlockfile; - cb.tc_malloc_lock = _thread_malloc_lock; - cb.tc_malloc_unlock = _thread_malloc_unlock; - cb.tc_atexit_lock = _thread_atexit_lock; - cb.tc_atexit_unlock = _thread_atexit_unlock; - cb.tc_atfork_lock = _thread_atfork_lock; - cb.tc_atfork_unlock = _thread_atfork_unlock; - cb.tc_arc4_lock = _thread_arc4_lock; - cb.tc_arc4_unlock = _thread_arc4_unlock; - cb.tc_mutex_lock = _thread_mutex_lock; - cb.tc_mutex_unlock = _thread_mutex_unlock; - cb.tc_mutex_destroy = _thread_mutex_destroy; - cb.tc_tag_lock = _thread_tag_lock; - cb.tc_tag_unlock = _thread_tag_unlock; - cb.tc_tag_storage = _thread_tag_storage; cb.tc_fork = _thread_fork; cb.tc_vfork = _thread_vfork; + cb.tc_thread_release = _thread_release; + cb.tc_thread_key_zero = _thread_key_zero; _thread_set_callbacks(&cb, sizeof(cb)); } @@ -253,27 +245,6 @@ _rthread_init(void) } static void -_rthread_free(pthread_t thread) -{ - _spinlock(&_thread_gc_lock); - TAILQ_INSERT_TAIL(&_thread_gc_list, thread, waiting); - _spinunlock(&_thread_gc_lock); -} - -/* - * real pthread functions - */ -pthread_t -pthread_self(void) -{ - if (!_threads_ready) - _rthread_init(); - - return (TIB_GET()->tib_thread); -} -DEF_STD(pthread_self); - -static void _rthread_reaper(void) { pthread_t thread; @@ -301,55 +272,9 @@ restart: _spinunlock(&_thread_gc_lock); } -void -pthread_exit(void *retval) -{ - struct rthread_cleanup_fn *clfn; - struct tib *tib = TIB_GET(); - pthread_t thread; - - if (!_threads_ready) - _rthread_init(); - thread = tib->tib_thread; - - if (tib->tib_cantcancel & CANCEL_DYING) { - /* - * Called pthread_exit() from destructor or cancelation - * handler: blow up. XXX write something to stderr? - */ - abort(); - //_exit(42); - } - - tib->tib_cantcancel |= CANCEL_DYING; - - thread->retval = retval; - - for (clfn = thread->cleanup_fns; clfn; ) { - struct rthread_cleanup_fn *oclfn = clfn; - clfn = clfn->next; - oclfn->fn(oclfn->arg); - free(oclfn); - } - _rthread_tls_destructors(thread); - _spinlock(&_thread_lock); - LIST_REMOVE(thread, threads); - _spinunlock(&_thread_lock); - - _spinlock(&thread->flags_lock); - if (thread->flags & THREAD_DETACHED) { - _spinunlock(&thread->flags_lock); - _rthread_free(thread); - } else { - thread->flags |= THREAD_DONE; - _spinunlock(&thread->flags_lock); - _sem_post(&thread->donesem); - } - - __threxit(&tib->tib_tid); - for(;;); -} -DEF_STD(pthread_exit); +/* + * real pthread functions + */ int pthread_join(pthread_t thread, void **retval) @@ -500,12 +425,6 @@ pthread_kill(pthread_t thread, int sig) } int -pthread_equal(pthread_t t1, pthread_t t2) -{ - return (t1 == t2); -} - -int pthread_cancel(pthread_t thread) { struct tib *tib = thread->tib; diff --git a/lib/librthread/rthread.h b/lib/librthread/rthread.h index cf041aacbe1..6f8c857f203 100644 --- a/lib/librthread/rthread.h +++ b/lib/librthread/rthread.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread.h,v 1.62 2017/08/01 08:57:48 kettenis Exp $ */ +/* $OpenBSD: rthread.h,v 1.63 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * All Rights Reserved. @@ -27,9 +27,11 @@ * THE MACHINE DEPENDENT CERROR CODE HAS HARD CODED OFFSETS INTO PTHREAD_T! */ -#include <sys/queue.h> +#ifndef _RTHREAD_H_ +#define _RTHREAD_H_ + #include <semaphore.h> -#include <machine/spinlock.h> +#include "thread_private.h" #ifdef __LP64__ #define RTHREAD_STACK_SIZE_DEF (512 * 1024) @@ -37,8 +39,6 @@ #define RTHREAD_STACK_SIZE_DEF (256 * 1024) #endif -#define _SPINLOCK_UNLOCKED _ATOMIC_LOCK_UNLOCKED - struct stack { SLIST_ENTRY(stack) link; /* link for free default stacks */ void *sp; /* machine stack pointer */ @@ -48,59 +48,9 @@ struct stack { size_t len; /* total size of allocated stack */ }; -struct __sem { - _atomic_lock_t lock; - volatile int waitcount; - volatile int value; - int shared; -}; - -TAILQ_HEAD(pthread_queue, pthread); - -#ifdef FUTEX - -struct pthread_mutex { - volatile unsigned int lock; - int type; - pthread_t owner; - int count; - int prioceiling; -}; - -struct pthread_cond { - volatile unsigned int seq; - clockid_t clock; - struct pthread_mutex *mutex; -}; - -#else - -struct pthread_mutex { - _atomic_lock_t lock; - struct pthread_queue lockers; - int type; - pthread_t owner; - int count; - int prioceiling; -}; - -struct pthread_cond { - _atomic_lock_t lock; - struct pthread_queue waiters; - struct pthread_mutex *mutex; - clockid_t clock; -}; -#endif /* FUTEX */ - -struct pthread_mutex_attr { - int ma_type; - int ma_protocol; - int ma_prioceiling; -}; +#define PTHREAD_MIN_PRIORITY 0 +#define PTHREAD_MAX_PRIORITY 31 -struct pthread_cond_attr { - clockid_t ca_clock; -}; struct pthread_rwlock { _atomic_lock_t lock; @@ -113,37 +63,6 @@ struct pthread_rwlockattr { int pshared; }; -struct pthread_attr { - void *stack_addr; - size_t stack_size; - size_t guard_size; - int detach_state; - int contention_scope; - int sched_policy; - struct sched_param sched_param; - int sched_inherit; -}; - -#define PTHREAD_MIN_PRIORITY 0 -#define PTHREAD_MAX_PRIORITY 31 - -struct rthread_key { - int used; - void (*destructor)(void *); -}; - -struct rthread_storage { - int keyid; - struct rthread_storage *next; - void *data; -}; - -struct rthread_cleanup_fn { - void (*fn)(void *); - void *arg; - struct rthread_cleanup_fn *next; -}; - struct pthread_barrier { pthread_mutex_t mutex; pthread_cond_t cond; @@ -162,61 +81,20 @@ struct pthread_spinlock { pthread_t owner; }; -struct tib; -struct pthread { - struct __sem donesem; - unsigned int flags; - _atomic_lock_t flags_lock; - struct tib *tib; - void *retval; - void *(*fn)(void *); - void *arg; - char name[32]; - struct stack *stack; - LIST_ENTRY(pthread) threads; - TAILQ_ENTRY(pthread) waiting; - pthread_cond_t blocking_cond; - struct pthread_attr attr; - struct rthread_storage *local_storage; - struct rthread_cleanup_fn *cleanup_fns; - int myerrno; - - /* cancel received in a delayed cancel block? */ - int delayed_cancel; -}; -/* flags in pthread->flags */ -#define THREAD_DONE 0x001 -#define THREAD_DETACHED 0x002 - -/* flags in tib->tib_thread_flags */ -#define TIB_THREAD_ASYNC_CANCEL 0x001 -#define TIB_THREAD_INITIAL_STACK 0x002 /* has stack from exec */ - -#define ENTER_DELAYED_CANCEL_POINT(tib, self) \ - (self)->delayed_cancel = 0; \ - ENTER_CANCEL_POINT_INNER(tib, 1, 1) #define ROUND_TO_PAGE(size) \ (((size) + (_thread_pagesize - 1)) & ~(_thread_pagesize - 1)) __BEGIN_HIDDEN_DECLS -void _spinlock(volatile _atomic_lock_t *); -int _spinlocktry(volatile _atomic_lock_t *); -void _spinunlock(volatile _atomic_lock_t *); int _sem_wait(sem_t, int, const struct timespec *, int *); int _sem_post(sem_t); void _rthread_init(void); struct stack *_rthread_alloc_stack(pthread_t); void _rthread_free_stack(struct stack *); -void _rthread_tls_destructors(pthread_t); -void _rthread_debug(int, const char *, ...) - __attribute__((__format__ (printf, 2, 3))); -void _rthread_debug_init(void); #ifndef NO_PIC void _rthread_dl_lock(int what); #endif -void _thread_malloc_reinit(void); extern int _threads_ready; extern size_t _thread_pagesize; @@ -227,10 +105,6 @@ __END_HIDDEN_DECLS void _thread_dump_info(void); -/* syscalls not declared in system headers */ #define REDIRECT_SYSCALL(x) typeof(x) x asm("_thread_sys_"#x) -void __threxit(pid_t *); -int __thrsleep(const volatile void *, clockid_t, const struct timespec *, - volatile void *, const int *); -int __thrwakeup(const volatile void *, int n); -int __thrsigdivert(sigset_t, siginfo_t *, const struct timespec *); + +#endif /* _RTHREAD_H_ */ diff --git a/lib/librthread/rthread_attr.c b/lib/librthread/rthread_attr.c index c25ae9c3faa..ceba9e8fb8a 100644 --- a/lib/librthread/rthread_attr.c +++ b/lib/librthread/rthread_attr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_attr.c,v 1.22 2016/05/07 19:05:22 guenther Exp $ */ +/* $OpenBSD: rthread_attr.c,v 1.23 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * All Rights Reserved. @@ -143,6 +143,9 @@ pthread_attr_getstacksize(const pthread_attr_t *attrp, size_t *stacksize) int pthread_attr_setstacksize(pthread_attr_t *attrp, size_t stacksize) { + if (!_threads_ready) /* for ROUND_TO_PAGE */ + _rthread_init(); + if (stacksize < PTHREAD_STACK_MIN || stacksize > ROUND_TO_PAGE(stacksize)) return (EINVAL); @@ -162,6 +165,9 @@ pthread_attr_getstackaddr(const pthread_attr_t *attrp, void **stackaddr) int pthread_attr_setstackaddr(pthread_attr_t *attrp, void *stackaddr) { + if (!_threads_ready) + _rthread_init(); /* for _thread_pagesize */ + if (stackaddr == NULL || (uintptr_t)stackaddr & (_thread_pagesize - 1)) return (EINVAL); (*attrp)->stack_addr = stackaddr; diff --git a/lib/librthread/rthread_cb.h b/lib/librthread/rthread_cb.h index b91922b25ad..c86155af5ab 100644 --- a/lib/librthread/rthread_cb.h +++ b/lib/librthread/rthread_cb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_cb.h,v 1.2 2016/09/01 10:41:02 otto Exp $ */ +/* $OpenBSD: rthread_cb.h,v 1.3 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2016 Philip Guenther <guenther@openbsd.org> * All Rights Reserved. @@ -16,26 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <stdio.h> - __BEGIN_HIDDEN_DECLS pid_t _thread_fork(void); pid_t _thread_vfork(void); -void _thread_flockfile(FILE *); -int _thread_ftrylockfile(FILE *); -void _thread_funlockfile(FILE *); -void _thread_malloc_lock(int); -void _thread_malloc_unlock(int); -void _thread_atexit_lock(void); -void _thread_atexit_unlock(void); -void _thread_atfork_lock(void); -void _thread_atfork_unlock(void); -void _thread_arc4_lock(void); -void _thread_arc4_unlock(void); -void _thread_mutex_lock(void **); -void _thread_mutex_unlock(void **); -void _thread_mutex_destroy(void **); -void _thread_tag_lock(void **); -void _thread_tag_unlock(void **); -void *_thread_tag_storage(void **, void *, size_t, void *); __END_HIDDEN_DECLS diff --git a/lib/librthread/rthread_cond.c b/lib/librthread/rthread_cond.c deleted file mode 100644 index b9f53fbea9a..00000000000 --- a/lib/librthread/rthread_cond.c +++ /dev/null @@ -1,216 +0,0 @@ -/* $OpenBSD: rthread_cond.c,v 1.3 2017/07/29 16:42:10 deraadt Exp $ */ -/* - * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org> - * Copyright (c) 2012 Philip Guenther <guenther@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#include <pthread.h> - -#include "rthread.h" -#include "cancel.h" -#include "synch.h" - -int -pthread_cond_init(pthread_cond_t *condp, const pthread_condattr_t *attr) -{ - pthread_cond_t cond; - - cond = calloc(1, sizeof(*cond)); - if (cond == NULL) - return (ENOMEM); - - if (attr == NULL) - cond->clock = CLOCK_REALTIME; - else - cond->clock = (*attr)->ca_clock; - *condp = cond; - - return (0); -} -DEF_STD(pthread_cond_init); - -int -pthread_cond_destroy(pthread_cond_t *condp) -{ - pthread_cond_t cond; - - assert(condp != NULL); - cond = *condp; - - if (cond != NULL) { - if (cond->mutex != NULL) { -#define MSG "pthread_cond_destroy on condvar with waiters!\n" - write(2, MSG, sizeof(MSG) - 1); -#undef MSG - return (EBUSY); - } - free(cond); - } - *condp = NULL; - - return (0); -} -DEF_STD(pthread_cond_destroy); - -int -_rthread_cond_timedwait(pthread_cond_t cond, pthread_mutex_t *mutexp, - const struct timespec *abs) -{ - struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp; - struct tib *tib = TIB_GET(); - pthread_t self = tib->tib_thread; - int error, rv = 0, canceled = 0, mutex_count = 0; - clockid_t clock = cond->clock; - int seq = cond->seq; - PREP_CANCEL_POINT(tib); - - _rthread_debug(5, "%p: cond_timed %p,%p (%p)\n", self, - (void *)cond, (void *)mutex, (void *)mutex->owner); - - ENTER_DELAYED_CANCEL_POINT(tib, self); - -#if notyet - /* mark the condvar as being associated with this mutex */ - if (cond->mutex == NULL) - atomic_cas_ptr(&cond->mutex, NULL, mutex); - - if (cond->mutex != mutex) { - LEAVE_CANCEL_POINT_INNER(tib, 1); - return (EINVAL); - } -#endif - - /* snag the count in case this is a recursive mutex */ - if (mutex->type == PTHREAD_MUTEX_RECURSIVE) - mutex_count = mutex->count; - - pthread_mutex_unlock(mutexp); - - do { - /* If ``seq'' wraps you deserve to lose a signal. */ - error = _twait(&cond->seq, seq, clock, abs); - /* - * If we took a normal signal (not from cancellation) then - * we should just go back to sleep without changing state - * (timeouts, etc). - */ - } while ((error == EINTR) && - (tib->tib_canceled == 0 || (tib->tib_cantcancel & CANCEL_DISABLED))); - - /* if timeout or canceled, make note of that */ - if (error == ETIMEDOUT) - rv = ETIMEDOUT; - else if (error == EINTR) - canceled = 1; - - pthread_mutex_lock(mutexp); - - /* restore the mutex's count */ - if (mutex->type == PTHREAD_MUTEX_RECURSIVE) - mutex->count = mutex_count; - - LEAVE_CANCEL_POINT_INNER(tib, canceled); - - return rv; -} - -int -pthread_cond_timedwait(pthread_cond_t *condp, pthread_mutex_t *mutexp, - const struct timespec *abs) -{ - pthread_cond_t cond; - int error; - - if (*condp == NULL) { - if ((error = pthread_cond_init(condp, NULL))) - return (error); - } - - cond = *condp; - if (abs == NULL || abs->tv_sec < 0 || abs->tv_nsec < 0 || - abs->tv_nsec >= 1000000000) - return (EINVAL); - - return (_rthread_cond_timedwait(cond, mutexp, abs)); -} - -int -pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp) -{ - pthread_cond_t cond; - int error; - - if (*condp == NULL) { - if ((error = pthread_cond_init(condp, NULL))) - return (error); - } - - cond = *condp; - return (_rthread_cond_timedwait(cond, mutexp, NULL)); -} -DEF_STD(pthread_cond_wait); - -int -pthread_cond_signal(pthread_cond_t *condp) -{ - pthread_cond_t cond; - int count; - - if (*condp == NULL) - return (0); - - cond = *condp; - - atomic_inc_int(&cond->seq); - count = _wake(&cond->seq, 1); - - _rthread_debug(5, "%p: cond_signal %p, %d awaken\n", pthread_self(), - (void *)cond, count); - - return (0); -} -DEF_STD(pthread_cond_signal); - -int -pthread_cond_broadcast(pthread_cond_t *condp) -{ - pthread_cond_t cond; - int count; - - if (*condp == NULL) - return (0); - - cond = *condp; - - atomic_inc_int(&cond->seq); -#if notyet - count = _requeue(&cond->seq, 1, INT_MAX, &cond->mutex->lock); -#else - count = _wake(&cond->seq, INT_MAX); -#endif - - _rthread_debug(5, "%p: cond_broadcast %p, %d awaken\n", pthread_self(), - (void *)cond, count); - - return (0); -} -DEF_STD(pthread_cond_broadcast); diff --git a/lib/librthread/rthread_condattr.c b/lib/librthread/rthread_condattr.c deleted file mode 100644 index 24c8e74089d..00000000000 --- a/lib/librthread/rthread_condattr.c +++ /dev/null @@ -1,71 +0,0 @@ -/* $OpenBSD: rthread_condattr.c,v 1.1 2012/02/23 04:43:06 guenther Exp $ */ -/* - * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> - * Copyright (c) 2012 Philip Guenther <guenther@openbsd.org> - * All Rights Reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* - * Condition Variable Attributes - */ - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#include <pthread.h> - -#include "rthread.h" - -int -pthread_condattr_init(pthread_condattr_t *attrp) -{ - pthread_condattr_t attr; - - attr = calloc(1, sizeof(*attr)); - if (!attr) - return (errno); - attr->ca_clock = CLOCK_REALTIME; - *attrp = attr; - - return (0); -} - -int -pthread_condattr_destroy(pthread_condattr_t *attrp) -{ - free(*attrp); - *attrp = NULL; - - return (0); -} - -int -pthread_condattr_getclock(const pthread_condattr_t *attr, clockid_t *clock_id) -{ - *clock_id = (*attr)->ca_clock; - return (0); -} - -int -pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id) -{ - if (clock_id != CLOCK_REALTIME && clock_id != CLOCK_MONOTONIC) - return (EINVAL); - (*attr)->ca_clock = clock_id; - return (0); -} - diff --git a/lib/librthread/rthread_debug.c b/lib/librthread/rthread_debug.c deleted file mode 100644 index 4115bc7b077..00000000000 --- a/lib/librthread/rthread_debug.c +++ /dev/null @@ -1,76 +0,0 @@ -/* $OpenBSD: rthread_debug.c,v 1.5 2016/09/01 10:56:46 deraadt Exp $ */ - -/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ - -#include <pthread.h> -#include <stdarg.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> - -#include "rthread.h" - -REDIRECT_SYSCALL(issetugid); - -int _rthread_debug_level; - -/* - * Note: messages truncated at 255 characters. Could use vasprintf, - * but don't want to use malloc here so the function can be used - * in signal handlers. - */ -#define MAX_MSG_LEN 256 -#define RTHREAD_ENV_DEBUG "RTHREAD_DEBUG" - -/* - * format and send output to stderr if the given "level" is less than or - * equal to the current debug level. Messages with a level <= 0 will - * always be printed. - */ -void -_rthread_debug(int level, const char *fmt, ...) -{ - char msg[MAX_MSG_LEN]; - char *p; - int cnt; - ssize_t c; - - if (_rthread_debug_level >= level) { - va_list ap; - va_start(ap, fmt); - cnt = vsnprintf(msg, MAX_MSG_LEN, fmt, ap); - va_end(ap); - if (cnt > MAX_MSG_LEN - 1) - cnt = MAX_MSG_LEN - 1; - p = msg; - do { - c = write(STDERR_FILENO, p, cnt); - if (c == -1) - break; - if (c != cnt) - sched_yield(); - p += c; - cnt -= c; - } while (cnt > 0); - } -} - -/* - * set the debug level from an environment string. Bogus values are - * silently ignored. - */ -void -_rthread_debug_init(void) -{ - char *envp; - char *rem; - - if (issetugid()) - return; - envp = getenv(RTHREAD_ENV_DEBUG); - if (envp) { - _rthread_debug_level = (int) strtol(envp, &rem, 0); - if (*rem || _rthread_debug_level < 0) - _rthread_debug_level = 0; - } -} diff --git a/lib/librthread/rthread_file.c b/lib/librthread/rthread_file.c deleted file mode 100644 index 100ceaff545..00000000000 --- a/lib/librthread/rthread_file.c +++ /dev/null @@ -1,303 +0,0 @@ -/* $OpenBSD: rthread_file.c,v 1.10 2016/09/04 10:13:35 akfaew Exp $ */ -/* - * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. - * 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 John Birrell. - * 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 JOHN BIRRELL 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 THE AUTHOR 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: uthread_file.c,v 1.9 1999/08/28 00:03:32 peter Exp $ - * - * POSIX stdio FILE locking functions. These assume that the locking - * is only required at FILE structure level, not at file descriptor - * level too. - * - */ -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/queue.h> -#include <pthread.h> -#include "rthread.h" -#include "rthread_cb.h" - -/* - * The FILE lock structure. The FILE *fp is locked if the owner is - * not NULL. If not locked, the file lock structure can be - * reassigned to a different file by setting fp. - */ -struct file_lock { - LIST_ENTRY(file_lock) entry; /* Entry if file list. */ - FILE *fp; /* The target file. */ - struct pthread_queue lockers; - pthread_t owner; - int count; -}; - -/* - * The number of file lock lists into which the file pointer is - * hashed. Ideally, the FILE structure size would have been increased, - * but this causes incompatibility, so separate data structures are - * required. - */ -#define NUM_HEADS 128 - -/* - * This macro casts a file pointer to a long integer and right - * shifts this by the number of bytes in a pointer. The shifted - * value is then remaindered using the maximum number of hash - * entries to produce and index into the array of static lock - * structures. If there is a collision, a linear search of the - * dynamic list of locks linked to each static lock is perfomed. - */ -#define file_idx(_p) ((int)((((uintptr_t) _p) >> sizeof(void *)) % NUM_HEADS)) - -/* - * Global array of file locks. The first lock for each hash bucket is - * allocated statically in the hope that there won't be too many - * collisions that require a malloc and an element added to the list. - */ -static struct static_file_lock { - LIST_HEAD(file_list_head, file_lock) head; - struct file_lock fl; -} flh[NUM_HEADS]; - -/* Lock for accesses to the hash table: */ -static _atomic_lock_t hash_lock = _SPINLOCK_UNLOCKED; - -/* - * Find a lock structure for a FILE, return NULL if the file is - * not locked: - */ -static -struct file_lock * -find_lock(int idx, FILE *fp) -{ - struct file_lock *p; - - /* Check if the file is locked using the static structure: */ - if (flh[idx].fl.fp == fp && flh[idx].fl.owner != NULL) - /* Return a pointer to the static lock: */ - p = &flh[idx].fl; - else { - /* Point to the first dynamic lock: */ - p = LIST_FIRST(&flh[idx].head); - - /* - * Loop through the dynamic locks looking for the - * target file: - */ - while (p != NULL && (p->fp != fp || p->owner == NULL)) - /* Not this file, try the next: */ - p = LIST_NEXT(p, entry); - } - return(p); -} - -/* - * Lock a file, assuming that there is no lock structure currently - * assigned to it. - */ -static -struct file_lock * -do_lock(int idx, FILE *fp) -{ - struct file_lock *p; - - /* Check if the static structure is not being used: */ - if (flh[idx].fl.owner == NULL) { - /* Return a pointer to the static lock: */ - p = &flh[idx].fl; - } - else { - /* Point to the first dynamic lock: */ - p = LIST_FIRST(&flh[idx].head); - - /* - * Loop through the dynamic locks looking for a - * lock structure that is not being used: - */ - while (p != NULL && p->owner != NULL) - /* This one is used, try the next: */ - p = LIST_NEXT(p, entry); - } - - /* - * If an existing lock structure has not been found, - * allocate memory for a new one: - */ - if (p == NULL && (p = (struct file_lock *) - malloc(sizeof(struct file_lock))) != NULL) { - /* Add the new element to the list: */ - LIST_INSERT_HEAD(&flh[idx].head, p, entry); - } - - /* Check if there is a lock structure to acquire: */ - if (p != NULL) { - /* Acquire the lock for the running thread: */ - p->fp = fp; - p->owner = pthread_self(); - p->count = 1; - TAILQ_INIT(&p->lockers); - } - return(p); -} - -void -_thread_flockfile(FILE * fp) -{ - int idx = file_idx(fp); - struct file_lock *p; - pthread_t self = pthread_self(); - - /* Lock the hash table: */ - _spinlock(&hash_lock); - - /* Get a pointer to any existing lock for the file: */ - if ((p = find_lock(idx, fp)) == NULL) { - /* - * The file is not locked, so this thread can - * grab the lock: - */ - do_lock(idx, fp); - - /* - * The file is already locked, so check if the - * running thread is the owner: - */ - } else if (p->owner == self) { - /* - * The running thread is already the - * owner, so increment the count of - * the number of times it has locked - * the file: - */ - p->count++; - } else { - /* - * The file is locked for another thread. - * Append this thread to the queue of - * threads waiting on the lock. - */ - TAILQ_INSERT_TAIL(&p->lockers,self,waiting); - while (p->owner != self) { - __thrsleep(self, 0, NULL, &hash_lock, NULL); - _spinlock(&hash_lock); - } - } - - /* Unlock the hash table: */ - _spinunlock(&hash_lock); -} - -int -_thread_ftrylockfile(FILE * fp) -{ - int ret = -1; - int idx = file_idx(fp); - struct file_lock *p; - - /* Lock the hash table: */ - _spinlock(&hash_lock); - - /* Get a pointer to any existing lock for the file: */ - if ((p = find_lock(idx, fp)) == NULL) { - /* - * The file is not locked, so this thread can - * grab the lock: - */ - p = do_lock(idx, fp); - - /* - * The file is already locked, so check if the - * running thread is the owner: - */ - } else if (p->owner == pthread_self()) { - /* - * The running thread is already the - * owner, so increment the count of - * the number of times it has locked - * the file: - */ - p->count++; - } else { - /* - * The file is locked for another thread, - * so this try fails. - */ - p = NULL; - } - - /* Unlock the hash table: */ - _spinunlock(&hash_lock); - - /* Check if the lock was obtained: */ - if (p != NULL) - /* Return success: */ - ret = 0; - - return (ret); -} - -void -_thread_funlockfile(FILE * fp) -{ - int idx = file_idx(fp); - struct file_lock *p; - - /* Lock the hash table: */ - _spinlock(&hash_lock); - - /* - * Get a pointer to the lock for the file and check that - * the running thread is the one with the lock: - */ - if ((p = find_lock(idx, fp)) != NULL && p->owner == pthread_self()) { - /* - * Check if this thread has locked the FILE - * more than once: - */ - if (--p->count == 0) { - /* Get the new owner of the lock: */ - if ((p->owner = TAILQ_FIRST(&p->lockers)) != NULL) { - /* Pop the thread off the queue: */ - TAILQ_REMOVE(&p->lockers,p->owner,waiting); - - /* - * This is the first lock for the new - * owner: - */ - p->count = 1; - - __thrwakeup(p->owner, 1); - } - } - } - - /* Unlock the hash table: */ - _spinunlock(&hash_lock); -} diff --git a/lib/librthread/rthread_fork.c b/lib/librthread/rthread_fork.c index ea13bdaed57..937b00a66f0 100644 --- a/lib/librthread/rthread_fork.c +++ b/lib/librthread/rthread_fork.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_fork.c,v 1.21 2017/07/30 19:48:30 tedu Exp $ */ +/* $OpenBSD: rthread_fork.c,v 1.22 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2008 Kurt Miller <kurt@openbsd.org> @@ -38,12 +38,11 @@ #include <errno.h> #include <pthread.h> +#include <stdio.h> #include <stdlib.h> #include <tib.h> #include <unistd.h> -#include "thread_private.h" /* in libc/include */ - #include "rthread.h" #include "rthread_cb.h" @@ -57,7 +56,6 @@ _dofork(pid_t (*sys_fork)(void)) { pthread_t me; pid_t newid; - int i; extern int _post_threaded; if (!_threads_ready) @@ -77,20 +75,7 @@ _dofork(pid_t (*sys_fork)(void)) _rthread_dl_lock(0); #endif - _thread_atexit_lock(); - for (i = 0; i < _MALLOC_MUTEXES; i++) - _thread_malloc_lock(i); - _thread_arc4_lock(); - - newid = sys_fork(); - - _thread_arc4_unlock(); - if (newid == 0) - _thread_malloc_reinit(); - else - for (i = 0; i < _MALLOC_MUTEXES; i++) - _thread_malloc_unlock(i); - _thread_atexit_unlock(); + newid = _thread_dofork(sys_fork); if (newid == 0) { struct tib *tib = me->tib; diff --git a/lib/librthread/rthread_libc.c b/lib/librthread/rthread_libc.c deleted file mode 100644 index 645c5605fd1..00000000000 --- a/lib/librthread/rthread_libc.c +++ /dev/null @@ -1,262 +0,0 @@ -/* $OpenBSD: rthread_libc.c,v 1.18 2017/05/27 14:20:39 mpi Exp $ */ - -/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ - -#include <sys/time.h> - -#include <pthread.h> -#include <stdlib.h> -#include <string.h> - -#include "thread_private.h" /* in libc/include */ - -#include "rthread.h" -#include "rthread_cb.h" - -/* - * A thread tag is a pointer to a structure of this type. An opaque - * tag is used to decouple libc from the thread library. - */ -struct _thread_tag { - pthread_mutex_t m; /* the tag's mutex */ - pthread_key_t k; /* a key for private data */ -}; - -/* - * local mutex to protect against tag creation races. - */ -static pthread_mutex_t _thread_tag_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* - * Initialize a thread tag structure once. This function is called - * if the tag is null. Allocation and initialization are controlled - * by a mutex. If the tag is not null when the mutex is obtained - * the caller lost a race -- some other thread initialized the tag. - * This function will never return NULL. - */ -static void -_thread_tag_init(void **tag) -{ - struct _thread_tag *tt; - int result; - - result = pthread_mutex_lock(&_thread_tag_mutex); - if (result == 0) { - if (*tag == NULL) { - tt = malloc(sizeof *tt); - if (tt != NULL) { - result = pthread_mutex_init(&tt->m, NULL); - result |= pthread_key_create(&tt->k, free); - *tag = tt; - } - } - result |= pthread_mutex_unlock(&_thread_tag_mutex); - } - if (result != 0) - _rthread_debug(1, "tag init failure"); -} - -/* - * lock the mutex associated with the given tag - */ -void -_thread_tag_lock(void **tag) -{ - struct _thread_tag *tt; - - if (__isthreaded) { - if (*tag == NULL) - _thread_tag_init(tag); - tt = *tag; - if (pthread_mutex_lock(&tt->m) != 0) - _rthread_debug(1, "tag mutex lock failure"); - } -} - -/* - * unlock the mutex associated with the given tag - */ -void -_thread_tag_unlock(void **tag) -{ - struct _thread_tag *tt; - - if (__isthreaded) { - if (*tag == NULL) - _thread_tag_init(tag); - tt = *tag; - if (pthread_mutex_unlock(&tt->m) != 0) - _rthread_debug(1, "tag mutex unlock failure"); - } -} - -/* - * return the thread specific data for the given tag. If there - * is no data for this thread initialize it from 'storage'. - * On any error return 'err'. - */ -void * -_thread_tag_storage(void **tag, void *storage, size_t sz, void *err) -{ - struct _thread_tag *tt; - void *ret; - - if (*tag == NULL) - _thread_tag_init(tag); - tt = *tag; - - ret = pthread_getspecific(tt->k); - if (ret == NULL) { - ret = malloc(sz); - if (ret == NULL) - ret = err; - else { - if (pthread_setspecific(tt->k, ret) == 0) - memcpy(ret, storage, sz); - else { - free(ret); - ret = err; - } - } - } - return ret; -} - -void -_thread_mutex_lock(void **mutex) -{ - pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex; - - if (pthread_mutex_lock(pmutex) != 0) - _rthread_debug(1, "mutex lock failure"); -} - -void -_thread_mutex_unlock(void **mutex) -{ - pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex; - - if (pthread_mutex_unlock(pmutex) != 0) - _rthread_debug(1, "mutex unlock failure"); -} - -void -_thread_mutex_destroy(void **mutex) -{ - pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex; - - if (pthread_mutex_destroy(pmutex) != 0) - _rthread_debug(1, "mutex destroy failure"); -} - -/* - * the malloc lock - */ -#ifndef FUTEX -#define MALLOC_LOCK_INITIALIZER(n) { \ - _SPINLOCK_UNLOCKED, \ - TAILQ_HEAD_INITIALIZER(malloc_lock[n].lockers), \ - PTHREAD_MUTEX_DEFAULT, \ - NULL, \ - 0, \ - -1 } -#else -#define MALLOC_LOCK_INITIALIZER(n) { \ - _SPINLOCK_UNLOCKED, \ - PTHREAD_MUTEX_DEFAULT, \ - NULL, \ - 0, \ - -1 } -#endif - -static struct pthread_mutex malloc_lock[_MALLOC_MUTEXES] = { - MALLOC_LOCK_INITIALIZER(0), - MALLOC_LOCK_INITIALIZER(1), - MALLOC_LOCK_INITIALIZER(2), - MALLOC_LOCK_INITIALIZER(3) -}; - -static pthread_mutex_t malloc_mutex[_MALLOC_MUTEXES] = { - &malloc_lock[0], - &malloc_lock[1], - &malloc_lock[2], - &malloc_lock[3] -}; - -void -_thread_malloc_lock(int i) -{ - pthread_mutex_lock(&malloc_mutex[i]); -} - -void -_thread_malloc_unlock(int i) -{ - pthread_mutex_unlock(&malloc_mutex[i]); -} - -void -_thread_malloc_reinit(void) -{ - int i; - - for (i = 0; i < _MALLOC_MUTEXES; i++) { - malloc_lock[i].lock = _SPINLOCK_UNLOCKED; -#ifndef FUTEX - TAILQ_INIT(&malloc_lock[i].lockers); -#endif - malloc_lock[i].owner = NULL; - malloc_lock[i].count = 0; - } -} - -/* - * atexit lock - */ -static _atomic_lock_t atexit_lock = _SPINLOCK_UNLOCKED; - -void -_thread_atexit_lock(void) -{ - _spinlock(&atexit_lock); -} - -void -_thread_atexit_unlock(void) -{ - _spinunlock(&atexit_lock); -} - -/* - * atfork lock - */ -static _atomic_lock_t atfork_lock = _SPINLOCK_UNLOCKED; - -void -_thread_atfork_lock(void) -{ - _spinlock(&atfork_lock); -} - -void -_thread_atfork_unlock(void) -{ - _spinunlock(&atfork_lock); -} - -/* - * arc4random lock - */ -static _atomic_lock_t arc4_lock = _SPINLOCK_UNLOCKED; - -void -_thread_arc4_lock(void) -{ - _spinlock(&arc4_lock); -} - -void -_thread_arc4_unlock(void) -{ - _spinunlock(&arc4_lock); -} diff --git a/lib/librthread/rthread_mutex.c b/lib/librthread/rthread_mutex.c deleted file mode 100644 index 0b72c90d88f..00000000000 --- a/lib/librthread/rthread_mutex.c +++ /dev/null @@ -1,288 +0,0 @@ -/* $OpenBSD: rthread_mutex.c,v 1.5 2017/07/29 16:42:10 deraadt Exp $ */ -/* - * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org> - * Copyright (c) 2012 Philip Guenther <guenther@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#include <pthread.h> - -#include "rthread.h" -#include "cancel.h" -#include "synch.h" - -/* - * States defined in "Futexes Are Tricky" 5.2 - */ -enum { - UNLOCKED = 0, - LOCKED = 1, /* locked without waiter */ - CONTENDED = 2, /* threads waiting for this mutex */ -}; - -#define SPIN_COUNT 128 -#if defined(__i386__) || defined(__amd64__) -#define SPIN_WAIT() asm volatile("pause": : : "memory") -#else -#define SPIN_WAIT() do { } while (0) -#endif - -static _atomic_lock_t static_init_lock = _SPINLOCK_UNLOCKED; - -int -pthread_mutex_init(pthread_mutex_t *mutexp, const pthread_mutexattr_t *attr) -{ - pthread_mutex_t mutex; - - mutex = calloc(1, sizeof(*mutex)); - if (mutex == NULL) - return (ENOMEM); - - if (attr == NULL) { - mutex->type = PTHREAD_MUTEX_DEFAULT; - mutex->prioceiling = -1; - } else { - mutex->type = (*attr)->ma_type; - mutex->prioceiling = (*attr)->ma_protocol == - PTHREAD_PRIO_PROTECT ? (*attr)->ma_prioceiling : -1; - } - *mutexp = mutex; - - return (0); -} -DEF_STD(pthread_mutex_init); - -int -pthread_mutex_destroy(pthread_mutex_t *mutexp) -{ - pthread_mutex_t mutex; - - if (mutexp == NULL || *mutexp == NULL) - return (EINVAL); - - mutex = *mutexp; - if (mutex) { - if (mutex->lock != UNLOCKED) { -#define MSG "pthread_mutex_destroy on mutex with waiters!\n" - write(2, MSG, sizeof(MSG) - 1); -#undef MSG - return (EBUSY); - } - free((void *)mutex); - *mutexp = NULL; - } - - return (0); -} -DEF_STD(pthread_mutex_destroy); - -static int -_rthread_mutex_trylock(pthread_mutex_t mutex, int trywait, - const struct timespec *abs) -{ - pthread_t self = pthread_self(); - - if (atomic_cas_uint(&mutex->lock, UNLOCKED, LOCKED) == UNLOCKED) { - membar_enter_after_atomic(); - mutex->owner = self; - return (0); - } - - if (mutex->owner == self) { - int type = mutex->type; - - /* already owner? handle recursive behavior */ - if (type != PTHREAD_MUTEX_RECURSIVE) { - if (trywait || type == PTHREAD_MUTEX_ERRORCHECK) - return (trywait ? EBUSY : EDEADLK); - - /* self-deadlock is disallowed by strict */ - if (type == PTHREAD_MUTEX_STRICT_NP && abs == NULL) - abort(); - - /* self-deadlock, possibly until timeout */ - while (_twait(&mutex->type, type, CLOCK_REALTIME, - abs) != ETIMEDOUT) - ; - return (ETIMEDOUT); - } else { - if (mutex->count == INT_MAX) - return (EAGAIN); - mutex->count++; - return (0); - } - } - - return (EBUSY); -} - -static int -_rthread_mutex_timedlock(pthread_mutex_t *mutexp, int trywait, - const struct timespec *abs, int timed) -{ - pthread_t self = pthread_self(); - pthread_mutex_t mutex; - unsigned int i, lock; - int error = 0; - - if (mutexp == NULL) - return (EINVAL); - - /* - * If the mutex is statically initialized, perform the dynamic - * initialization. Note: _thread_mutex_lock() in libc requires - * pthread_mutex_lock() to perform the mutex init when *mutexp - * is NULL. - */ - if (*mutexp == NULL) { - _spinlock(&static_init_lock); - if (*mutexp == NULL) - error = pthread_mutex_init(mutexp, NULL); - _spinunlock(&static_init_lock); - if (error != 0) - return (EINVAL); - } - - mutex = *mutexp; - _rthread_debug(5, "%p: mutex_%slock %p (%p)\n", self, - (timed ? "timed" : (trywait ? "try" : "")), (void *)mutex, - (void *)mutex->owner); - - error = _rthread_mutex_trylock(mutex, trywait, abs); - if (error != EBUSY || trywait) - return (error); - - /* Try hard to not enter the kernel. */ - for (i = 0; i < SPIN_COUNT; i ++) { - if (mutex->lock == UNLOCKED) - break; - - SPIN_WAIT(); - } - - lock = atomic_cas_uint(&mutex->lock, UNLOCKED, LOCKED); - if (lock == UNLOCKED) { - membar_enter_after_atomic(); - mutex->owner = self; - return (0); - } - - if (lock != CONTENDED) { - /* Indicate that we're waiting on this mutex. */ - lock = atomic_swap_uint(&mutex->lock, CONTENDED); - } - - while (lock != UNLOCKED) { - error = _twait(&mutex->lock, CONTENDED, CLOCK_REALTIME, abs); - if (error == ETIMEDOUT) - return (error); - /* - * We cannot know if there's another waiter, so in - * doubt set the state to CONTENDED. - */ - lock = atomic_swap_uint(&mutex->lock, CONTENDED); - }; - - membar_enter_after_atomic(); - mutex->owner = self; - return (0); -} - -int -pthread_mutex_trylock(pthread_mutex_t *mutexp) -{ - return (_rthread_mutex_timedlock(mutexp, 1, NULL, 0)); -} - -int -pthread_mutex_timedlock(pthread_mutex_t *mutexp, const struct timespec *abs) -{ - return (_rthread_mutex_timedlock(mutexp, 0, abs, 1)); -} - -int -pthread_mutex_lock(pthread_mutex_t *mutexp) -{ - return (_rthread_mutex_timedlock(mutexp, 0, NULL, 0)); -} -DEF_STD(pthread_mutex_lock); - -int -pthread_mutex_unlock(pthread_mutex_t *mutexp) -{ - pthread_t self = pthread_self(); - pthread_mutex_t mutex; - - if (mutexp == NULL) - return (EINVAL); - - if (*mutexp == NULL) -#if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_ERRORCHECK - return (EPERM); -#elif PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL - return(0); -#else - abort(); -#endif - - mutex = *mutexp; - _rthread_debug(5, "%p: mutex_unlock %p (%p)\n", self, (void *)mutex, - (void *)mutex->owner); - - if (mutex->owner != self) { - _rthread_debug(5, "%p: different owner %p (%p)\n", self, (void *)mutex, - (void *)mutex->owner); - if (mutex->type == PTHREAD_MUTEX_ERRORCHECK || - mutex->type == PTHREAD_MUTEX_RECURSIVE) { - return (EPERM); - } else { - /* - * For mutex type NORMAL our undefined behavior for - * unlocking an unlocked mutex is to succeed without - * error. All other undefined behaviors are to - * abort() immediately. - */ - if (mutex->owner == NULL && - mutex->type == PTHREAD_MUTEX_NORMAL) - return (0); - else - abort(); - - } - } - - if (mutex->type == PTHREAD_MUTEX_RECURSIVE) { - if (mutex->count > 0) { - mutex->count--; - return (0); - } - } - - mutex->owner = NULL; - membar_exit_before_atomic(); - if (atomic_dec_int_nv(&mutex->lock) != UNLOCKED) { - mutex->lock = UNLOCKED; - _wake(&mutex->lock, 1); - } - - return (0); -} -DEF_STD(pthread_mutex_unlock); diff --git a/lib/librthread/rthread_np.c b/lib/librthread/rthread_np.c index d8a78110358..86beb501068 100644 --- a/lib/librthread/rthread_np.c +++ b/lib/librthread/rthread_np.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_np.c,v 1.19 2016/05/07 19:05:22 guenther Exp $ */ +/* $OpenBSD: rthread_np.c,v 1.20 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * Copyright (c) 2005 Otto Moerbeek <otto@openbsd.org> @@ -80,6 +80,9 @@ pthread_stackseg_np(pthread_t thread, stack_t *sinfo) static struct rlimit rl; static int gotself; + if (!_threads_ready) /* for ROUND_TO_PAGE */ + _rthread_init(); + if (gotself == 0) { int mib[2]; size_t len; diff --git a/lib/librthread/rthread_sched.c b/lib/librthread/rthread_sched.c index 1df1ed19943..d81e5981387 100644 --- a/lib/librthread/rthread_sched.c +++ b/lib/librthread/rthread_sched.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_sched.c,v 1.13 2015/04/29 06:01:37 guenther Exp $ */ +/* $OpenBSD: rthread_sched.c,v 1.14 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * All Rights Reserved. @@ -32,6 +32,9 @@ int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param) { + if (!_threads_ready) + _rthread_init(); + *policy = thread->attr.sched_policy; if (param) *param = thread->attr.sched_param; @@ -43,6 +46,9 @@ int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param) { + if (!_threads_ready) + _rthread_init(); + /* XXX return ENOTSUP for SCHED_{FIFO,RR}? */ if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR) @@ -114,12 +120,18 @@ pthread_attr_setinheritsched(pthread_attr_t *attrp, int inherit) int pthread_getprio(pthread_t thread) { + if (!_threads_ready) + _rthread_init(); + return (thread->attr.sched_param.sched_priority); } int pthread_setprio(pthread_t thread, int priority) { + if (!_threads_ready) + _rthread_init(); + thread->attr.sched_param.sched_priority = priority; return (0); diff --git a/lib/librthread/rthread_sem.c b/lib/librthread/rthread_sem.c index 5d0e34294e7..196fb8ec357 100644 --- a/lib/librthread/rthread_sem.c +++ b/lib/librthread/rthread_sem.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_sem.c,v 1.25 2016/09/04 10:13:35 akfaew Exp $ */ +/* $OpenBSD: rthread_sem.c,v 1.26 2017/09/05 02:40:54 guenther Exp $ */ /* * Copyright (c) 2004,2005,2013 Ted Unangst <tedu@openbsd.org> * All Rights Reserved. @@ -172,6 +172,9 @@ sem_destroy(sem_t *semp) { sem_t sem; + if (!_threads_ready) /* for SEM_MMAP_SIZE */ + _rthread_init(); + if (!semp || !(sem = *semp)) { errno = EINVAL; return (-1); diff --git a/lib/librthread/rthread_stack.c b/lib/librthread/rthread_stack.c index 6d3ab3a9b7b..f40ca006c86 100644 --- a/lib/librthread/rthread_stack.c +++ b/lib/librthread/rthread_stack.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_stack.c,v 1.16 2016/09/04 10:13:35 akfaew Exp $ */ +/* $OpenBSD: rthread_stack.c,v 1.17 2017/09/05 02:40:54 guenther Exp $ */ /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ @@ -33,7 +33,7 @@ _rthread_alloc_stack(pthread_t thread) /* if the request uses the defaults, try to reuse one */ if (thread->attr.stack_addr == NULL && thread->attr.stack_size == RTHREAD_STACK_SIZE_DEF && - thread->attr.guard_size == _rthread_attr_default.guard_size) { + thread->attr.guard_size == _thread_pagesize) { _spinlock(&def_stacks_lock); stack = SLIST_FIRST(&def_stacks); if (stack != NULL) { @@ -123,7 +123,7 @@ void _rthread_free_stack(struct stack *stack) { if (stack->len == RTHREAD_STACK_SIZE_DEF + stack->guardsize && - stack->guardsize == _rthread_attr_default.guard_size) { + stack->guardsize == _thread_pagesize) { _spinlock(&def_stacks_lock); SLIST_INSERT_HEAD(&def_stacks, stack, link); _spinunlock(&def_stacks_lock); diff --git a/lib/librthread/rthread_sync.c b/lib/librthread/rthread_sync.c deleted file mode 100644 index 3f42916d713..00000000000 --- a/lib/librthread/rthread_sync.c +++ /dev/null @@ -1,693 +0,0 @@ -/* $OpenBSD: rthread_sync.c,v 1.46 2017/07/29 16:42:10 deraadt Exp $ */ -/* - * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> - * Copyright (c) 2012 Philip Guenther <guenther@openbsd.org> - * All Rights Reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* - * Mutexes and conditions - synchronization functions. - */ - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#include <pthread.h> - -#include "rthread.h" -#include "cancel.h" /* in libc/include */ - -static _atomic_lock_t static_init_lock = _SPINLOCK_UNLOCKED; - -/* - * mutexen - */ -int -pthread_mutex_init(pthread_mutex_t *mutexp, const pthread_mutexattr_t *attr) -{ - struct pthread_mutex *mutex; - - mutex = calloc(1, sizeof(*mutex)); - if (!mutex) - return (errno); - mutex->lock = _SPINLOCK_UNLOCKED; - TAILQ_INIT(&mutex->lockers); - if (attr == NULL) { - mutex->type = PTHREAD_MUTEX_DEFAULT; - mutex->prioceiling = -1; - } else { - mutex->type = (*attr)->ma_type; - mutex->prioceiling = (*attr)->ma_protocol == - PTHREAD_PRIO_PROTECT ? (*attr)->ma_prioceiling : -1; - } - *mutexp = mutex; - - return (0); -} -DEF_STD(pthread_mutex_init); - -int -pthread_mutex_destroy(pthread_mutex_t *mutexp) -{ - struct pthread_mutex *mutex; - - assert(mutexp); - mutex = (struct pthread_mutex *)*mutexp; - if (mutex) { - if (mutex->count || mutex->owner != NULL || - !TAILQ_EMPTY(&mutex->lockers)) { -#define MSG "pthread_mutex_destroy on mutex with waiters!\n" - write(2, MSG, sizeof(MSG) - 1); -#undef MSG - return (EBUSY); - } - free(mutex); - *mutexp = NULL; - } - return (0); -} -DEF_STD(pthread_mutex_destroy); - -static int -_rthread_mutex_lock(pthread_mutex_t *mutexp, int trywait, - const struct timespec *abstime) -{ - struct pthread_mutex *mutex; - pthread_t self = pthread_self(); - int ret = 0; - - /* - * If the mutex is statically initialized, perform the dynamic - * initialization. Note: _thread_mutex_lock() in libc requires - * _rthread_mutex_lock() to perform the mutex init when *mutexp - * is NULL. - */ - if (*mutexp == NULL) { - _spinlock(&static_init_lock); - if (*mutexp == NULL) - ret = pthread_mutex_init(mutexp, NULL); - _spinunlock(&static_init_lock); - if (ret != 0) - return (EINVAL); - } - mutex = (struct pthread_mutex *)*mutexp; - - _rthread_debug(5, "%p: mutex_lock %p\n", (void *)self, (void *)mutex); - _spinlock(&mutex->lock); - if (mutex->owner == NULL && TAILQ_EMPTY(&mutex->lockers)) { - assert(mutex->count == 0); - mutex->owner = self; - } else if (mutex->owner == self) { - assert(mutex->count > 0); - - /* already owner? handle recursive behavior */ - if (mutex->type != PTHREAD_MUTEX_RECURSIVE) - { - if (trywait || - mutex->type == PTHREAD_MUTEX_ERRORCHECK) { - _spinunlock(&mutex->lock); - return (trywait ? EBUSY : EDEADLK); - } - - /* self-deadlock is disallowed by strict */ - if (mutex->type == PTHREAD_MUTEX_STRICT_NP && - abstime == NULL) - abort(); - - /* self-deadlock, possibly until timeout */ - while (__thrsleep(self, CLOCK_REALTIME, abstime, - &mutex->lock, NULL) != EWOULDBLOCK) - _spinlock(&mutex->lock); - return (ETIMEDOUT); - } - if (mutex->count == INT_MAX) { - _spinunlock(&mutex->lock); - return (EAGAIN); - } - } else if (trywait) { - /* try failed */ - _spinunlock(&mutex->lock); - return (EBUSY); - } else { - /* add to the wait queue and block until at the head */ - TAILQ_INSERT_TAIL(&mutex->lockers, self, waiting); - while (mutex->owner != self) { - ret = __thrsleep(self, CLOCK_REALTIME, abstime, - &mutex->lock, NULL); - _spinlock(&mutex->lock); - assert(mutex->owner != NULL); - if (ret == EWOULDBLOCK) { - if (mutex->owner == self) - break; - TAILQ_REMOVE(&mutex->lockers, self, waiting); - _spinunlock(&mutex->lock); - return (ETIMEDOUT); - } - } - } - - mutex->count++; - _spinunlock(&mutex->lock); - - return (0); -} - -int -pthread_mutex_lock(pthread_mutex_t *p) -{ - return (_rthread_mutex_lock(p, 0, NULL)); -} -DEF_STD(pthread_mutex_lock); - -int -pthread_mutex_trylock(pthread_mutex_t *p) -{ - return (_rthread_mutex_lock(p, 1, NULL)); -} - -int -pthread_mutex_timedlock(pthread_mutex_t *p, const struct timespec *abstime) -{ - return (_rthread_mutex_lock(p, 0, abstime)); -} - -int -pthread_mutex_unlock(pthread_mutex_t *mutexp) -{ - pthread_t self = pthread_self(); - struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp; - - _rthread_debug(5, "%p: mutex_unlock %p\n", (void *)self, - (void *)mutex); - - if (mutex == NULL) -#if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_ERRORCHECK - return (EPERM); -#elif PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL - return(0); -#else - abort(); -#endif - - if (mutex->owner != self) { - if (mutex->type == PTHREAD_MUTEX_ERRORCHECK || - mutex->type == PTHREAD_MUTEX_RECURSIVE) - return (EPERM); - else { - /* - * For mutex type NORMAL our undefined behavior for - * unlocking an unlocked mutex is to succeed without - * error. All other undefined behaviors are to - * abort() immediately. - */ - if (mutex->owner == NULL && - mutex->type == PTHREAD_MUTEX_NORMAL) - return (0); - else - abort(); - } - } - - if (--mutex->count == 0) { - pthread_t next; - - _spinlock(&mutex->lock); - mutex->owner = next = TAILQ_FIRST(&mutex->lockers); - if (next != NULL) - TAILQ_REMOVE(&mutex->lockers, next, waiting); - _spinunlock(&mutex->lock); - if (next != NULL) - __thrwakeup(next, 1); - } - - return (0); -} -DEF_STD(pthread_mutex_unlock); - -/* - * condition variables - */ -int -pthread_cond_init(pthread_cond_t *condp, const pthread_condattr_t *attr) -{ - pthread_cond_t cond; - - cond = calloc(1, sizeof(*cond)); - if (!cond) - return (errno); - cond->lock = _SPINLOCK_UNLOCKED; - TAILQ_INIT(&cond->waiters); - if (attr == NULL) - cond->clock = CLOCK_REALTIME; - else - cond->clock = (*attr)->ca_clock; - *condp = cond; - - return (0); -} -DEF_STD(pthread_cond_init); - -int -pthread_cond_destroy(pthread_cond_t *condp) -{ - pthread_cond_t cond; - - assert(condp); - cond = *condp; - if (cond) { - if (!TAILQ_EMPTY(&cond->waiters)) { -#define MSG "pthread_cond_destroy on condvar with waiters!\n" - write(2, MSG, sizeof(MSG) - 1); -#undef MSG - return (EBUSY); - } - free(cond); - } - *condp = NULL; - - return (0); -} -DEF_STD(pthread_cond_destroy); - -int -pthread_cond_timedwait(pthread_cond_t *condp, pthread_mutex_t *mutexp, - const struct timespec *abstime) -{ - pthread_cond_t cond; - struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp; - struct tib *tib = TIB_GET(); - pthread_t self = tib->tib_thread; - pthread_t next; - int mutex_count; - int canceled = 0; - int rv = 0; - int error; - PREP_CANCEL_POINT(tib); - - if (!*condp) - if ((error = pthread_cond_init(condp, NULL))) - return (error); - cond = *condp; - _rthread_debug(5, "%p: cond_timed %p,%p\n", (void *)self, - (void *)cond, (void *)mutex); - - if (mutex == NULL) -#if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_ERRORCHECK - return (EPERM); -#else - abort(); -#endif - - if (mutex->owner != self) { - if (mutex->type == PTHREAD_MUTEX_ERRORCHECK) - return (EPERM); - else - abort(); - } - - if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || - abstime->tv_nsec >= 1000000000) - return (EINVAL); - - ENTER_DELAYED_CANCEL_POINT(tib, self); - - _spinlock(&cond->lock); - - /* mark the condvar as being associated with this mutex */ - if (cond->mutex == NULL) { - cond->mutex = mutex; - assert(TAILQ_EMPTY(&cond->waiters)); - } else if (cond->mutex != mutex) { - assert(cond->mutex == mutex); - _spinunlock(&cond->lock); - LEAVE_CANCEL_POINT_INNER(tib, 1); - return (EINVAL); - } else - assert(! TAILQ_EMPTY(&cond->waiters)); - - /* snag the count in case this is a recursive mutex */ - mutex_count = mutex->count; - - /* transfer from the mutex queue to the condvar queue */ - _spinlock(&mutex->lock); - self->blocking_cond = cond; - TAILQ_INSERT_TAIL(&cond->waiters, self, waiting); - _spinunlock(&cond->lock); - - /* wake the next guy blocked on the mutex */ - mutex->count = 0; - mutex->owner = next = TAILQ_FIRST(&mutex->lockers); - if (next != NULL) { - TAILQ_REMOVE(&mutex->lockers, next, waiting); - __thrwakeup(next, 1); - } - - /* wait until we're the owner of the mutex again */ - while (mutex->owner != self) { - error = __thrsleep(self, cond->clock, abstime, - &mutex->lock, &self->delayed_cancel); - - /* - * If abstime == NULL, then we're definitely waiting - * on the mutex instead of the condvar, and are - * just waiting for mutex ownership, regardless of - * why we woke up. - */ - if (abstime == NULL) { - _spinlock(&mutex->lock); - continue; - } - - /* - * If we took a normal signal (not from - * cancellation) then we should just go back to - * sleep without changing state (timeouts, etc). - */ - if (error == EINTR && (tib->tib_canceled == 0 || - (tib->tib_cantcancel & CANCEL_DISABLED))) { - _spinlock(&mutex->lock); - continue; - } - - /* - * The remaining reasons for waking up (normal - * wakeup, timeout, and cancellation) all mean that - * we won't be staying in the condvar queue and - * we'll no longer time out or be cancelable. - */ - abstime = NULL; - LEAVE_CANCEL_POINT_INNER(tib, 0); - - /* - * If we're no longer in the condvar's queue then - * we're just waiting for mutex ownership. Need - * cond->lock here to prevent race with cond_signal(). - */ - _spinlock(&cond->lock); - if (self->blocking_cond == NULL) { - _spinunlock(&cond->lock); - _spinlock(&mutex->lock); - continue; - } - assert(self->blocking_cond == cond); - - /* if timeout or canceled, make note of that */ - if (error == EWOULDBLOCK) - rv = ETIMEDOUT; - else if (error == EINTR) - canceled = 1; - - /* transfer between the queues */ - TAILQ_REMOVE(&cond->waiters, self, waiting); - assert(mutex == cond->mutex); - if (TAILQ_EMPTY(&cond->waiters)) - cond->mutex = NULL; - self->blocking_cond = NULL; - _spinunlock(&cond->lock); - _spinlock(&mutex->lock); - - /* mutex unlocked right now? */ - if (mutex->owner == NULL && - TAILQ_EMPTY(&mutex->lockers)) { - assert(mutex->count == 0); - mutex->owner = self; - break; - } - TAILQ_INSERT_TAIL(&mutex->lockers, self, waiting); - } - - /* restore the mutex's count */ - mutex->count = mutex_count; - _spinunlock(&mutex->lock); - - LEAVE_CANCEL_POINT_INNER(tib, canceled); - - return (rv); -} - -int -pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp) -{ - pthread_cond_t cond; - struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp; - struct tib *tib = TIB_GET(); - pthread_t self = tib->tib_thread; - pthread_t next; - int mutex_count; - int canceled = 0; - int error; - PREP_CANCEL_POINT(tib); - - if (!*condp) - if ((error = pthread_cond_init(condp, NULL))) - return (error); - cond = *condp; - _rthread_debug(5, "%p: cond_wait %p,%p\n", (void *)self, - (void *)cond, (void *)mutex); - - if (mutex == NULL) -#if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_ERRORCHECK - return (EPERM); -#else - abort(); -#endif - - if (mutex->owner != self) { - if (mutex->type == PTHREAD_MUTEX_ERRORCHECK) - return (EPERM); - else - abort(); - } - - ENTER_DELAYED_CANCEL_POINT(tib, self); - - _spinlock(&cond->lock); - - /* mark the condvar as being associated with this mutex */ - if (cond->mutex == NULL) { - cond->mutex = mutex; - assert(TAILQ_EMPTY(&cond->waiters)); - } else if (cond->mutex != mutex) { - assert(cond->mutex == mutex); - _spinunlock(&cond->lock); - LEAVE_CANCEL_POINT_INNER(tib, 1); - return (EINVAL); - } else - assert(! TAILQ_EMPTY(&cond->waiters)); - - /* snag the count in case this is a recursive mutex */ - mutex_count = mutex->count; - - /* transfer from the mutex queue to the condvar queue */ - _spinlock(&mutex->lock); - self->blocking_cond = cond; - TAILQ_INSERT_TAIL(&cond->waiters, self, waiting); - _spinunlock(&cond->lock); - - /* wake the next guy blocked on the mutex */ - mutex->count = 0; - mutex->owner = next = TAILQ_FIRST(&mutex->lockers); - if (next != NULL) { - TAILQ_REMOVE(&mutex->lockers, next, waiting); - __thrwakeup(next, 1); - } - - /* wait until we're the owner of the mutex again */ - while (mutex->owner != self) { - error = __thrsleep(self, 0, NULL, &mutex->lock, - &self->delayed_cancel); - - /* - * If we took a normal signal (not from - * cancellation) then we should just go back to - * sleep without changing state (timeouts, etc). - */ - if (error == EINTR && (tib->tib_canceled == 0 || - (tib->tib_cantcancel & CANCEL_DISABLED))) { - _spinlock(&mutex->lock); - continue; - } - - /* - * The remaining reasons for waking up (normal - * wakeup and cancellation) all mean that we won't - * be staying in the condvar queue and we'll no - * longer be cancelable. - */ - LEAVE_CANCEL_POINT_INNER(tib, 0); - - /* - * If we're no longer in the condvar's queue then - * we're just waiting for mutex ownership. Need - * cond->lock here to prevent race with cond_signal(). - */ - _spinlock(&cond->lock); - if (self->blocking_cond == NULL) { - _spinunlock(&cond->lock); - _spinlock(&mutex->lock); - continue; - } - assert(self->blocking_cond == cond); - - /* if canceled, make note of that */ - if (error == EINTR) - canceled = 1; - - /* transfer between the queues */ - TAILQ_REMOVE(&cond->waiters, self, waiting); - assert(mutex == cond->mutex); - if (TAILQ_EMPTY(&cond->waiters)) - cond->mutex = NULL; - self->blocking_cond = NULL; - _spinunlock(&cond->lock); - _spinlock(&mutex->lock); - - /* mutex unlocked right now? */ - if (mutex->owner == NULL && - TAILQ_EMPTY(&mutex->lockers)) { - assert(mutex->count == 0); - mutex->owner = self; - break; - } - TAILQ_INSERT_TAIL(&mutex->lockers, self, waiting); - } - - /* restore the mutex's count */ - mutex->count = mutex_count; - _spinunlock(&mutex->lock); - - LEAVE_CANCEL_POINT_INNER(tib, canceled); - - return (0); -} -DEF_STD(pthread_cond_wait); - - -int -pthread_cond_signal(pthread_cond_t *condp) -{ - pthread_cond_t cond; - struct pthread_mutex *mutex; - pthread_t thread; - int wakeup; - - /* uninitialized? Then there's obviously no one waiting! */ - if (!*condp) - return 0; - - cond = *condp; - _rthread_debug(5, "%p: cond_signal %p,%p\n", (void *)pthread_self(), - (void *)cond, (void *)cond->mutex); - _spinlock(&cond->lock); - thread = TAILQ_FIRST(&cond->waiters); - if (thread == NULL) { - assert(cond->mutex == NULL); - _spinunlock(&cond->lock); - return (0); - } - - assert(thread->blocking_cond == cond); - TAILQ_REMOVE(&cond->waiters, thread, waiting); - thread->blocking_cond = NULL; - - mutex = cond->mutex; - assert(mutex != NULL); - if (TAILQ_EMPTY(&cond->waiters)) - cond->mutex = NULL; - - /* link locks to prevent race with timedwait */ - _spinlock(&mutex->lock); - _spinunlock(&cond->lock); - - wakeup = mutex->owner == NULL && TAILQ_EMPTY(&mutex->lockers); - if (wakeup) - mutex->owner = thread; - else - TAILQ_INSERT_TAIL(&mutex->lockers, thread, waiting); - _spinunlock(&mutex->lock); - if (wakeup) - __thrwakeup(thread, 1); - - return (0); -} -DEF_STD(pthread_cond_signal); - -int -pthread_cond_broadcast(pthread_cond_t *condp) -{ - pthread_cond_t cond; - struct pthread_mutex *mutex; - pthread_t thread; - pthread_t p; - int wakeup; - - /* uninitialized? Then there's obviously no one waiting! */ - if (!*condp) - return 0; - - cond = *condp; - _rthread_debug(5, "%p: cond_broadcast %p,%p\n", (void *)pthread_self(), - (void *)cond, (void *)cond->mutex); - _spinlock(&cond->lock); - thread = TAILQ_FIRST(&cond->waiters); - if (thread == NULL) { - assert(cond->mutex == NULL); - _spinunlock(&cond->lock); - return (0); - } - - mutex = cond->mutex; - assert(mutex != NULL); - - /* walk the list, clearing the "blocked on condvar" pointer */ - p = thread; - do - p->blocking_cond = NULL; - while ((p = TAILQ_NEXT(p, waiting)) != NULL); - - /* - * We want to transfer all the threads from the condvar's list - * to the mutex's list. The TAILQ_* macros don't let us do that - * efficiently, so this is direct list surgery. Pay attention! - */ - - /* 1) attach the first thread to the end of the mutex's list */ - _spinlock(&mutex->lock); - wakeup = mutex->owner == NULL && TAILQ_EMPTY(&mutex->lockers); - thread->waiting.tqe_prev = mutex->lockers.tqh_last; - *(mutex->lockers.tqh_last) = thread; - - /* 2) fix up the end pointer for the mutex's list */ - mutex->lockers.tqh_last = cond->waiters.tqh_last; - - if (wakeup) { - TAILQ_REMOVE(&mutex->lockers, thread, waiting); - mutex->owner = thread; - _spinunlock(&mutex->lock); - __thrwakeup(thread, 1); - } else - _spinunlock(&mutex->lock); - - /* 3) reset the condvar's list and mutex pointer */ - TAILQ_INIT(&cond->waiters); - assert(cond->mutex != NULL); - cond->mutex = NULL; - _spinunlock(&cond->lock); - - return (0); -} -DEF_STD(pthread_cond_broadcast); diff --git a/lib/librthread/rthread_tls.c b/lib/librthread/rthread_tls.c deleted file mode 100644 index 7118132dfd2..00000000000 --- a/lib/librthread/rthread_tls.c +++ /dev/null @@ -1,185 +0,0 @@ -/* $OpenBSD: rthread_tls.c,v 1.18 2016/09/04 10:13:35 akfaew Exp $ */ -/* - * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> - * All Rights Reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* - * thread specific storage - */ - -#include <stdlib.h> -#include <errno.h> - -#include <pthread.h> - -#include "rthread.h" - -static struct rthread_key rkeys[PTHREAD_KEYS_MAX]; -static _atomic_lock_t rkeyslock = _SPINLOCK_UNLOCKED; - -int -pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) -{ - static int hint; - int i; - - _spinlock(&rkeyslock); - if (rkeys[hint].used) { - for (i = 0; i < PTHREAD_KEYS_MAX; i++) { - if (!rkeys[i].used) - break; - } - if (i == PTHREAD_KEYS_MAX) { - _spinunlock(&rkeyslock); - return (EAGAIN); - } - hint = i; - } - rkeys[hint].used = 1; - rkeys[hint].destructor = destructor; - - *key = hint++; - if (hint >= PTHREAD_KEYS_MAX) - hint = 0; - _spinunlock(&rkeyslock); - - return (0); -} -DEF_STD(pthread_key_create); - -int -pthread_key_delete(pthread_key_t key) -{ - pthread_t thread; - struct rthread_storage *rs; - int rv = 0; - - if (key < 0 || key >= PTHREAD_KEYS_MAX) - return (EINVAL); - - _spinlock(&rkeyslock); - if (!rkeys[key].used) { - rv = EINVAL; - goto out; - } - - rkeys[key].used = 0; - rkeys[key].destructor = NULL; - _spinlock(&_thread_lock); - LIST_FOREACH(thread, &_thread_list, threads) { - for (rs = thread->local_storage; rs; rs = rs->next) { - if (rs->keyid == key) - rs->data = NULL; - } - } - _spinunlock(&_thread_lock); - -out: - _spinunlock(&rkeyslock); - return (rv); -} - -static struct rthread_storage * -_rthread_findstorage(pthread_key_t key) -{ - struct rthread_storage *rs; - pthread_t self; - - if (!rkeys[key].used) { - rs = NULL; - goto out; - } - - self = pthread_self(); - - for (rs = self->local_storage; rs; rs = rs->next) { - if (rs->keyid == key) - break; - } - if (!rs) { - rs = calloc(1, sizeof(*rs)); - if (!rs) - goto out; - rs->keyid = key; - rs->data = NULL; - rs->next = self->local_storage; - self->local_storage = rs; - } - -out: - return (rs); -} - -void * -pthread_getspecific(pthread_key_t key) -{ - struct rthread_storage *rs; - - if (key < 0 || key >= PTHREAD_KEYS_MAX) - return (NULL); - - rs = _rthread_findstorage(key); - if (!rs) - return (NULL); - - return (rs->data); -} -DEF_STD(pthread_getspecific); - -int -pthread_setspecific(pthread_key_t key, const void *data) -{ - struct rthread_storage *rs; - - if (key < 0 || key >= PTHREAD_KEYS_MAX) - return (EINVAL); - - rs = _rthread_findstorage(key); - if (!rs) - return (ENOMEM); - rs->data = (void *)data; - - return (0); -} -DEF_STD(pthread_setspecific); - -void -_rthread_tls_destructors(pthread_t thread) -{ - struct rthread_storage *rs; - int i; - - _spinlock(&rkeyslock); - for (i = 0; i < PTHREAD_DESTRUCTOR_ITERATIONS; i++) { - for (rs = thread->local_storage; rs; rs = rs->next) { - if (!rs->data) - continue; - if (rkeys[rs->keyid].destructor) { - void (*destructor)(void *) = - rkeys[rs->keyid].destructor; - void *data = rs->data; - rs->data = NULL; - _spinunlock(&rkeyslock); - destructor(data); - _spinlock(&rkeyslock); - } - } - } - for (rs = thread->local_storage; rs; rs = thread->local_storage) { - thread->local_storage = rs->next; - free(rs); - } - _spinunlock(&rkeyslock); -} diff --git a/lib/librthread/shlib_version b/lib/librthread/shlib_version index df4de0fc4dc..906022aa66d 100644 --- a/lib/librthread/shlib_version +++ b/lib/librthread/shlib_version @@ -1,2 +1,2 @@ -major=23 +major=24 minor=0 diff --git a/lib/librthread/synch.h b/lib/librthread/synch.h deleted file mode 100644 index 0c69a39164e..00000000000 --- a/lib/librthread/synch.h +++ /dev/null @@ -1,63 +0,0 @@ -/* $OpenBSD: synch.h,v 1.2 2017/05/29 14:47:54 mpi Exp $ */ -/* - * Copyright (c) 2017 Martin Pieuchot - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/atomic.h> -#include <sys/time.h> -#include <sys/futex.h> - -REDIRECT_SYSCALL(futex); - -static inline int -_wake(volatile uint32_t *p, int n) -{ - return futex(p, FUTEX_WAKE, n, NULL, NULL); -} - -static inline void -_wait(volatile uint32_t *p, int val) -{ - while (*p != (uint32_t)val) - futex(p, FUTEX_WAIT, val, NULL, NULL); -} - -static inline int -_twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *abs) -{ - struct timespec rel; - - if (abs == NULL) - return futex(p, FUTEX_WAIT, val, NULL, NULL); - - if (abs->tv_nsec >= 1000000000 || clock_gettime(clockid, &rel)) - return (EINVAL); - - rel.tv_sec = abs->tv_sec - rel.tv_sec; - if ((rel.tv_nsec = abs->tv_nsec - rel.tv_nsec) < 0) { - rel.tv_sec--; - rel.tv_nsec += 1000000000; - } - if (rel.tv_sec < 0) - return (ETIMEDOUT); - - return futex(p, FUTEX_WAIT, val, &rel, NULL); -} - -static inline int -_requeue(volatile uint32_t *p, int n, int m, volatile uint32_t *q) -{ - return futex(p, FUTEX_REQUEUE, n, (void *)(long)m, q); -} |