Skip to content

Commit

Permalink
macOS: workaround a dyld/libunwind deadlock issue since 12.1
Browse files Browse the repository at this point in the history
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
  • Loading branch information
vtjnash committed Jan 12, 2022
1 parent fd8b2ab commit 2939272
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ endif
CLANG_LDFLAGS := $(LLVM_LDFLAGS)
ifeq ($(OS), Darwin)
CLANG_LDFLAGS += -Wl,-undefined,dynamic_lookup
OSLIBS += $(SRCDIR)/mach_dyld_atfork.tbd
endif

COMMON_LIBPATHS := -L$(build_libdir) -L$(build_shlibdir)
Expand Down
25 changes: 25 additions & 0 deletions src/mach_dyld_atfork.tbd
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--- !tapi-tbd
# copied from XCode's libSystem.tbd (current-version: 1311)
# to provide weak-linkage info for new symbols on old systems
tbd-version: 4
targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos, arm64-maccatalyst,
arm64e-macos, arm64e-maccatalyst ]
uuids:
- target: x86_64-macos
value: AFE6C76A-B47A-35F5-91D0-4E9FC439E90D
- target: x86_64-maccatalyst
value: AFE6C76A-B47A-35F5-91D0-4E9FC439E90D
- target: arm64-macos
value: 2EA09BDB-811B-33AA-BB58-4B53AA2DB522
- target: arm64-maccatalyst
value: 2EA09BDB-811B-33AA-BB58-4B53AA2DB522
- target: arm64e-macos
value: 09AB3723-C26D-3762-93BA-98E9C38B89C1
- target: arm64e-maccatalyst
value: 09AB3723-C26D-3762-93BA-98E9C38B89C1
install-name: '/usr/lib/libSystem.B.dylib'
exports:
- targets: [ arm64-macos, arm64e-macos, x86_64-macos, x86_64-maccatalyst,
arm64-maccatalyst, arm64e-maccatalyst ]
symbols: [ __dyld_atfork_parent, __dyld_atfork_prepare ]
...
31 changes: 27 additions & 4 deletions src/signals-mach.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ extern void *_keymgr_get_and_lock_processwide_ptr(unsigned int key);
extern int _keymgr_get_and_lock_processwide_ptr_2(unsigned int key, void **result);
extern int _keymgr_set_lockmode_processwide_ptr(unsigned int key, unsigned int mode);

// private dyld3/dyld4 stuff
extern void _dyld_atfork_prepare(void) __attribute__((weak_import));
extern void _dyld_atfork_parent(void) __attribute__((weak_import));
//extern void _dyld_fork_child(void) __attribute__((weak_import));

static void attach_exception_port(thread_port_t thread, int segv_only);

// low 16 bits are the thread id, the next 8 bits are the original gc_state
Expand Down Expand Up @@ -521,6 +526,28 @@ static kern_return_t profiler_segv_handler
}
#endif

static int jl_lock_profile_mach(void)
{
jl_lock_profile();
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)
_dyld_atfork_prepare();
return keymgr_locked;
}

static void jl_unlock_profile_mach(int keymgr_locked)
{
if (_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)

void *mach_profile_listener(void *arg)
{
(void)arg;
Expand All @@ -538,8 +565,6 @@ void *mach_profile_listener(void *arg)
// sample each thread, round-robin style in reverse order
// (so that thread zero gets notified last)
jl_lock_profile();
void *unused = NULL;
int keymgr_locked = _keymgr_get_and_lock_processwide_ptr_2(KEYMGR_GCC3_DW2_OBJ_LIST, &unused) == 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.
Expand Down Expand Up @@ -609,8 +634,6 @@ void *mach_profile_listener(void *arg)
// We're done! Resume the thread.
jl_thread_resume(i, 0);
}
if (keymgr_locked)
_keymgr_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
jl_unlock_profile();
if (running) {
// Reset the alarm
Expand Down

0 comments on commit 2939272

Please sign in to comment.