Skip to content

Commit 3b8774b

Browse files
committed
macOS: extend the workaround to cover the dyld/exc_server deadlock issue, since 12.1
Later, we should probably switch to using mach_exc_server generated from `mig mach_exc.defs`.
1 parent 03c5769 commit 3b8774b

File tree

1 file changed

+16
-9
lines changed

1 file changed

+16
-9
lines changed

src/signals-mach.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -526,27 +526,30 @@ static kern_return_t profiler_segv_handler
526526
}
527527
#endif
528528

529-
static int jl_lock_profile_mach(void)
529+
// WARNING: we are unable to handle sigsegv while the dlsymlock is held
530+
static int jl_lock_profile_mach(int dlsymlock)
530531
{
531532
jl_lock_profile();
533+
// workaround for old keymgr bugs
532534
void *unused = NULL;
533535
int keymgr_locked = _keymgr_get_and_lock_processwide_ptr_2(KEYMGR_GCC3_DW2_OBJ_LIST, &unused) == 0;
534-
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
536+
// workaround for new dlsym4 bugs (API and bugs introduced in macOS 12.1)
537+
if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
535538
_dyld_atfork_prepare();
536539
return keymgr_locked;
537540
}
538541

539-
static void jl_unlock_profile_mach(int keymgr_locked)
542+
static void jl_unlock_profile_mach(int dlsymlock, int keymgr_locked)
540543
{
541-
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
542-
_dyld_atfork_parent();
544+
if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) \
545+
_dyld_atfork_parent(); \
543546
if (keymgr_locked)
544547
_keymgr_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
545548
jl_unlock_profile();
546549
}
547550

548-
#define jl_lock_profile() int keymgr_locked = jl_lock_profile_mach()
549-
#define jl_unlock_profile() jl_unlock_profile_mach(keymgr_locked)
551+
#define jl_lock_profile() int keymgr_locked = jl_lock_profile_mach(1)
552+
#define jl_unlock_profile() jl_unlock_profile_mach(1, keymgr_locked)
550553

551554
void *mach_profile_listener(void *arg)
552555
{
@@ -564,7 +567,7 @@ void *mach_profile_listener(void *arg)
564567
HANDLE_MACH_ERROR("mach_msg", ret);
565568
// sample each thread, round-robin style in reverse order
566569
// (so that thread zero gets notified last)
567-
jl_lock_profile();
570+
int keymgr_locked = jl_lock_profile_mach(0);
568571
jl_shuffle_int_array_inplace(profile_round_robin_thread_order, jl_n_threads, &profile_cong_rng_seed);
569572
for (int idx = jl_n_threads; idx-- > 0; ) {
570573
// Stop the threads in the random round-robin order.
@@ -575,9 +578,13 @@ void *mach_profile_listener(void *arg)
575578
break;
576579
}
577580

581+
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
582+
_dyld_atfork_prepare(); // briefly acquire the dlsym lock
578583
host_thread_state_t state;
579584
jl_thread_suspend_and_get_state2(i, &state);
580585
unw_context_t *uc = (unw_context_t*)&state;
586+
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
587+
_dyld_atfork_parent(); // quickly release the dlsym lock
581588

582589
if (running) {
583590
#ifdef LLVMLIBUNWIND
@@ -634,7 +641,7 @@ void *mach_profile_listener(void *arg)
634641
// We're done! Resume the thread.
635642
jl_thread_resume(i, 0);
636643
}
637-
jl_unlock_profile();
644+
jl_unlock_profile_mach(0, keymgr_locked);
638645
if (running) {
639646
// Reset the alarm
640647
kern_return_t ret = clock_alarm(clk, TIME_RELATIVE, timerprof, profile_port);

0 commit comments

Comments
 (0)