Skip to content

Commit 29f360a

Browse files
committed
macOS: workaround a dyld/libunwind deadlock issue since 12.1
Apple reintroduced the old bug that we previously worked around in fad04d3 with a similar patch to this. This is needed anywhere that we may attempt to stop threads. Fixes #43578
1 parent dbd10e0 commit 29f360a

File tree

1 file changed

+27
-4
lines changed

1 file changed

+27
-4
lines changed

src/signals-mach.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ extern void *_keymgr_get_and_lock_processwide_ptr(unsigned int key);
3131
extern int _keymgr_get_and_lock_processwide_ptr_2(unsigned int key, void **result);
3232
extern int _keymgr_set_lockmode_processwide_ptr(unsigned int key, unsigned int mode);
3333

34+
// private dyld3/dyld4 stuff
35+
extern void _dyld_atfork_prepare(void) __attribute__((weak_import));
36+
extern void _dyld_atfork_parent(void) __attribute__((weak_import));
37+
//extern void _dyld_fork_child(void) __attribute__((weak_import));
38+
3439
static void attach_exception_port(thread_port_t thread, int segv_only);
3540

3641
// low 16 bits are the thread id, the next 8 bits are the original gc_state
@@ -521,6 +526,28 @@ static kern_return_t profiler_segv_handler
521526
}
522527
#endif
523528

529+
static int jl_lock_profile_mach(void)
530+
{
531+
jl_lock_profile();
532+
void *unused = NULL;
533+
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)
535+
_dyld_atfork_prepare();
536+
return keymgr_locked;
537+
}
538+
539+
static void jl_unlock_profile_mach(int keymgr_locked)
540+
{
541+
if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL)
542+
_dyld_atfork_parent();
543+
if (keymgr_locked)
544+
_keymgr_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
545+
jl_unlock_profile();
546+
}
547+
548+
#define jl_lock_profile() int keymgr_locked = jl_lock_profile_mach()
549+
#define jl_unlock_profile() jl_unlock_profile_mach(keymgr_locked)
550+
524551
void *mach_profile_listener(void *arg)
525552
{
526553
(void)arg;
@@ -538,8 +565,6 @@ void *mach_profile_listener(void *arg)
538565
// sample each thread, round-robin style in reverse order
539566
// (so that thread zero gets notified last)
540567
jl_lock_profile();
541-
void *unused = NULL;
542-
int keymgr_locked = _keymgr_get_and_lock_processwide_ptr_2(KEYMGR_GCC3_DW2_OBJ_LIST, &unused) == 0;
543568
jl_shuffle_int_array_inplace(profile_round_robin_thread_order, jl_n_threads, &profile_cong_rng_seed);
544569
for (int idx = jl_n_threads; idx-- > 0; ) {
545570
// Stop the threads in the random round-robin order.
@@ -609,8 +634,6 @@ void *mach_profile_listener(void *arg)
609634
// We're done! Resume the thread.
610635
jl_thread_resume(i, 0);
611636
}
612-
if (keymgr_locked)
613-
_keymgr_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
614637
jl_unlock_profile();
615638
if (running) {
616639
// Reset the alarm

0 commit comments

Comments
 (0)