diff --git a/src/signals-mach.c b/src/signals-mach.c index 364c3dc64d667..4ddfad4e10600 100644 --- a/src/signals-mach.c +++ b/src/signals-mach.c @@ -526,27 +526,30 @@ static kern_return_t profiler_segv_handler } #endif -static int jl_lock_profile_mach(void) +// WARNING: we are unable to handle sigsegv while the dlsymlock is held +static int jl_lock_profile_mach(int dlsymlock) { jl_lock_profile(); + // workaround for old keymgr bugs void *unused = NULL; int keymgr_locked = _keymgr_get_and_lock_processwide_ptr_2(KEYMGR_GCC3_DW2_OBJ_LIST, &unused) == 0; - if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) + // workaround for new dlsym4 bugs (API and bugs introduced in macOS 12.1) + if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) _dyld_atfork_prepare(); return keymgr_locked; } -static void jl_unlock_profile_mach(int keymgr_locked) +static void jl_unlock_profile_mach(int dlsymlock, int keymgr_locked) { - if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) - _dyld_atfork_parent(); + if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) \ + _dyld_atfork_parent(); \ if (keymgr_locked) _keymgr_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); jl_unlock_profile(); } -#define jl_lock_profile() int keymgr_locked = jl_lock_profile_mach() -#define jl_unlock_profile() jl_unlock_profile_mach(keymgr_locked) +#define jl_lock_profile() int keymgr_locked = jl_lock_profile_mach(1) +#define jl_unlock_profile() jl_unlock_profile_mach(1, keymgr_locked) void *mach_profile_listener(void *arg) { @@ -564,7 +567,7 @@ void *mach_profile_listener(void *arg) HANDLE_MACH_ERROR("mach_msg", ret); // sample each thread, round-robin style in reverse order // (so that thread zero gets notified last) - jl_lock_profile(); + int keymgr_locked = jl_lock_profile_mach(0); jl_shuffle_int_array_inplace(profile_round_robin_thread_order, jl_n_threads, &profile_cong_rng_seed); for (int idx = jl_n_threads; idx-- > 0; ) { // Stop the threads in the random round-robin order. @@ -575,9 +578,13 @@ void *mach_profile_listener(void *arg) break; } + if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) + _dyld_atfork_prepare(); // briefly acquire the dlsym lock host_thread_state_t state; jl_thread_suspend_and_get_state2(i, &state); unw_context_t *uc = (unw_context_t*)&state; + if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) + _dyld_atfork_parent(); // quickly release the dlsym lock if (running) { #ifdef LLVMLIBUNWIND @@ -634,7 +641,7 @@ void *mach_profile_listener(void *arg) // We're done! Resume the thread. jl_thread_resume(i, 0); } - jl_unlock_profile(); + jl_unlock_profile_mach(0, keymgr_locked); if (running) { // Reset the alarm kern_return_t ret = clock_alarm(clk, TIME_RELATIVE, timerprof, profile_port);