diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 6e8bfce..2e64313 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -432,6 +432,8 @@ FBSDprivate_1.0 { _spinlock; _spinlock_debug; _spinunlock; + _rtld_atfork_pre; + _rtld_atfork_post; _rtld_error; /* for private use */ _rtld_thread_init; /* for private use */ _err; diff --git a/lib/libc/gen/dlfcn.c b/lib/libc/gen/dlfcn.c index 39ba141..eac3f1a 100644 --- a/lib/libc/gen/dlfcn.c +++ b/lib/libc/gen/dlfcn.c @@ -137,3 +137,15 @@ dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), _rtld_error(sorry); return 0; } + +#pragma weak _rtld_atfork_pre +void +_rtld_atfork_pre(int *locks) +{ +} + +#pragma weak _rtld_atfork_post +void +_rtld_atfork_post(int *locks) +{ +} diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 55bc413..b407cba 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -3114,6 +3114,8 @@ arena_lock_balance(arena_t *arena) { unsigned contention; + if (narenas > 1) + malloc_spin_lock(&arenas_lock); contention = malloc_spin_lock(&arena->lock); if (narenas > 1) { /* @@ -3126,6 +3128,7 @@ arena_lock_balance(arena_t *arena) + (uint64_t)contention) >> BALANCE_ALPHA_INV_2POW; if (arena->contention >= opt_balance_threshold) arena_lock_balance_hard(arena); + malloc_spin_unlock(&arenas_lock); } } @@ -3142,12 +3145,10 @@ arena_lock_balance_hard(arena_t *arena) if (arenas[ind] != NULL) arenas_map = arenas[ind]; else { - malloc_spin_lock(&arenas_lock); if (arenas[ind] != NULL) arenas_map = arenas[ind]; else arenas_map = arenas_extend(ind); - malloc_spin_unlock(&arenas_lock); } } #endif diff --git a/lib/libthr/thread/thr_fork.c b/lib/libthr/thread/thr_fork.c index 713e0b5..4ddd93a 100644 --- a/lib/libthr/thread/thr_fork.c +++ b/lib/libthr/thread/thr_fork.c @@ -67,6 +67,7 @@ #include "un-namespace.h" #include "libc_private.h" +#include "rtld_lock.h" #include "thr_private.h" __weak_reference(_pthread_atfork, pthread_atfork); @@ -105,6 +106,7 @@ _fork(void) pid_t ret; int errsave; int unlock_malloc; + int rtld_locks[16]; if (!_thr_is_inited()) return (__sys_fork()); @@ -126,7 +128,8 @@ _fork(void) */ if (_thr_isthreaded() != 0) { unlock_malloc = 1; - _malloc_prefork(); + _malloc_prefork(); + _rtld_atfork_pre(rtld_locks); } else { unlock_malloc = 0; } @@ -167,6 +170,11 @@ _fork(void) /* Ready to continue, unblock signals. */ _thr_signal_unblock(curthread); + if (unlock_malloc) { + _rtld_atfork_post(rtld_locks); + _malloc_postfork(); + } + /* Run down atfork child handlers. */ TAILQ_FOREACH(af, &_thr_atfork_list, qe) { if (af->child != NULL) @@ -179,8 +187,10 @@ _fork(void) /* Ready to continue, unblock signals. */ _thr_signal_unblock(curthread); - if (unlock_malloc) + if (unlock_malloc) { + _rtld_atfork_post(rtld_locks); _malloc_postfork(); + } /* Run down atfork parent handlers. */ TAILQ_FOREACH(af, &_thr_atfork_list, qe) { diff --git a/lib/libthr/thread/thr_rtld.c b/lib/libthr/thread/thr_rtld.c index a8cd61d..9101cc1 100644 --- a/lib/libthr/thread/thr_rtld.c +++ b/lib/libthr/thread/thr_rtld.c @@ -181,6 +181,7 @@ _thr_rtld_init(void) struct RtldLockInfo li; struct pthread *curthread; long dummy; + void *dummy1; curthread = _get_curthread(); @@ -190,6 +191,10 @@ _thr_rtld_init(void) /* force to resolve errno() PLT */ __error(); + /* force to resolve free() PLT */ + dummy1 = malloc(1); + free(dummy1); + li.lock_create = _thr_rtld_lock_create; li.lock_destroy = _thr_rtld_lock_destroy; li.rlock_acquire = _thr_rtld_rlock_acquire; @@ -203,6 +208,7 @@ _thr_rtld_init(void) _thr_signal_block(curthread); _rtld_thread_init(&li); _thr_signal_unblock(curthread); + } void diff --git a/libexec/rtld-elf/Symbol.map b/libexec/rtld-elf/Symbol.map index 325362c..20f8d60 100644 --- a/libexec/rtld-elf/Symbol.map +++ b/libexec/rtld-elf/Symbol.map @@ -21,4 +21,6 @@ FBSDprivate_1.0 { _rtld_thread_init; _rtld_allocate_tls; _rtld_free_tls; + _rtld_atfork_pre; + _rtld_atfork_post; }; diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 144ea6c..f67093a 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -206,6 +206,8 @@ static func_ptr_type exports[] = { (func_ptr_type) &_rtld_allocate_tls, (func_ptr_type) &_rtld_free_tls, (func_ptr_type) &dl_iterate_phdr, + (func_ptr_type) &_rtld_atfork_pre, + (func_ptr_type) &_rtld_atfork_post, NULL }; diff --git a/libexec/rtld-elf/rtld_lock.c b/libexec/rtld-elf/rtld_lock.c index 5bb891a..bf4caf7 100644 --- a/libexec/rtld-elf/rtld_lock.c +++ b/libexec/rtld-elf/rtld_lock.c @@ -316,3 +316,19 @@ _rtld_thread_init(struct RtldLockInfo *pli) thread_mask_set(flags); dbg("_rtld_thread_init: done"); } + +void +_rtld_atfork_pre(int *locks) +{ + + locks[2] = wlock_acquire(rtld_phdr_lock); + locks[0] = rlock_acquire(rtld_bind_lock); +} + +void +_rtld_atfork_post(int *locks) +{ + + rlock_release(rtld_bind_lock, locks[0]); + wlock_release(rtld_phdr_lock, locks[2]); +} diff --git a/libexec/rtld-elf/rtld_lock.h b/libexec/rtld-elf/rtld_lock.h index 2e3f954..4c5d854 100644 --- a/libexec/rtld-elf/rtld_lock.h +++ b/libexec/rtld-elf/rtld_lock.h @@ -44,6 +44,8 @@ struct RtldLockInfo }; extern void _rtld_thread_init(struct RtldLockInfo *); +extern void _rtld_atfork_pre(int *); +extern void _rtld_atfork_post(int *); #ifdef IN_RTLD