Skip to content

Commit 5ec2d68

Browse files
vtjnashKristofferC
authored andcommitted
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`. (cherry picked from commit 267b124)
1 parent e0ecf0e commit 5ec2d68

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
@@ -516,27 +516,30 @@ static kern_return_t profiler_segv_handler
516516
}
517517
#endif
518518

519-
static int jl_lock_profile_mach(void)
519+
// WARNING: we are unable to handle sigsegv while the dlsymlock is held
520+
static int jl_lock_profile_mach(int dlsymlock)
520521
{
521522
jl_lock_profile();
523+
// workaround for old keymgr bugs
522524
void *unused = NULL;
523525
int keymgr_locked = _keymgr_get_and_lock_processwide_ptr_2(KEYMGR_GCC3_DW2_OBJ_LIST, &unused) == 0;
524-
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
526+
// workaround for new dlsym4 bugs (API and bugs introduced in macOS 12.1)
527+
if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
525528
_dyld_atfork_prepare();
526529
return keymgr_locked;
527530
}
528531

529-
static void jl_unlock_profile_mach(int keymgr_locked)
532+
static void jl_unlock_profile_mach(int dlsymlock, int keymgr_locked)
530533
{
531-
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
532-
_dyld_atfork_parent();
534+
if (dlsymlock && _dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) \
535+
_dyld_atfork_parent(); \
533536
if (keymgr_locked)
534537
_keymgr_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
535538
jl_unlock_profile();
536539
}
537540

538-
#define jl_lock_profile() int keymgr_locked = jl_lock_profile_mach()
539-
#define jl_unlock_profile() jl_unlock_profile_mach(keymgr_locked)
541+
#define jl_lock_profile() int keymgr_locked = jl_lock_profile_mach(1)
542+
#define jl_unlock_profile() jl_unlock_profile_mach(1, keymgr_locked)
540543

541544
void *mach_profile_listener(void *arg)
542545
{
@@ -555,17 +558,21 @@ void *mach_profile_listener(void *arg)
555558
HANDLE_MACH_ERROR("mach_msg", ret);
556559
// sample each thread, round-robin style in reverse order
557560
// (so that thread zero gets notified last)
558-
jl_lock_profile();
561+
int keymgr_locked = jl_lock_profile_mach(0);
559562
for (i = jl_n_threads; i-- > 0; ) {
560563
// if there is no space left, break early
561564
if (jl_profile_is_buffer_full()) {
562565
jl_profile_stop_timer();
563566
break;
564567
}
565568

569+
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
570+
_dyld_atfork_prepare(); // briefly acquire the dlsym lock
566571
host_thread_state_t state;
567572
jl_thread_suspend_and_get_state2(i, &state);
568573
unw_context_t *uc = (unw_context_t*)&state;
574+
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
575+
_dyld_atfork_parent(); // quickly release the dlsym lock
569576

570577
if (running) {
571578
#ifdef LIBOSXUNWIND
@@ -608,7 +615,7 @@ void *mach_profile_listener(void *arg)
608615
// We're done! Resume the thread.
609616
jl_thread_resume(i, 0);
610617
}
611-
jl_unlock_profile();
618+
jl_unlock_profile_mach(0, keymgr_locked);
612619
if (running) {
613620
// Reset the alarm
614621
kern_return_t ret = clock_alarm(clk, TIME_RELATIVE, timerprof, profile_port);

0 commit comments

Comments
 (0)