Skip to content

Commit bb83a29

Browse files
vtjnashSacha0
authored andcommitted
backport of: macOS: workaround a keymgr/libunwind deadlock issue on x86_64 since 10.9
1 parent 6967e26 commit bb83a29

File tree

1 file changed

+27
-0
lines changed

1 file changed

+27
-0
lines changed

src/signals-mach.c

+27
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,18 @@
1717

1818
#include "julia_assert.h"
1919

20+
// private keymgr stuff
21+
#define KEYMGR_GCC3_DW2_OBJ_LIST 302
22+
enum {
23+
NM_ALLOW_RECURSION = 1,
24+
NM_RECURSION_ILLEGAL = 2
25+
};
26+
extern void _keymgr_set_and_unlock_processwide_ptr(unsigned int key, void *ptr);
27+
extern int _keymgr_unlock_processwide_ptr(unsigned int key);
28+
extern void *_keymgr_get_and_lock_processwide_ptr(unsigned int key);
29+
extern int _keymgr_get_and_lock_processwide_ptr_2(unsigned int key, void **result);
30+
extern int _keymgr_set_lockmode_processwide_ptr(unsigned int key, unsigned int mode);
31+
2032
static void attach_exception_port(thread_port_t thread, int segv_only);
2133

2234
// low 16 bits are the thread id, the next 8 bits are the original gc_state
@@ -78,6 +90,17 @@ void *mach_segv_listener(void *arg)
7890

7991
static void allocate_segv_handler()
8092
{
93+
// ensure KEYMGR_GCC3_DW2_OBJ_LIST is initialized, as this requires malloc
94+
// and thus can deadlock when used without first initializing it.
95+
// Apple caused this problem in their libunwind in 10.9 (circa keymgr-28)
96+
// when they removed this part of the code from keymgr.
97+
// Much thanks to Apple for providing source code, or this would probably
98+
// have simply remained unsolved forever on their platform.
99+
// This is similar to just calling checkKeyMgrRegisteredFDEs
100+
// (this is quite thread-unsafe)
101+
if (_keymgr_set_lockmode_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, NM_ALLOW_RECURSION))
102+
jl_error("_keymgr_set_lockmode_processwide_ptr failed");
103+
81104
arraylist_new(&suspended_threads, jl_n_threads);
82105
pthread_t thread;
83106
pthread_attr_t attr;
@@ -421,6 +444,8 @@ void *mach_profile_listener(void *arg)
421444
// sample each thread, round-robin style in reverse order
422445
// (so that thread zero gets notified last)
423446
jl_lock_profile();
447+
void *unused = NULL;
448+
int keymgr_locked = _keymgr_get_and_lock_processwide_ptr_2(KEYMGR_GCC3_DW2_OBJ_LIST, &unused) == 0;
424449
for (i = jl_n_threads; i-- > 0; ) {
425450
// if there is no space left, break early
426451
if (bt_size_cur >= bt_size_max - 1)
@@ -469,6 +494,8 @@ void *mach_profile_listener(void *arg)
469494
// We're done! Resume the thread.
470495
jl_thread_resume(i, 0);
471496
}
497+
if (keymgr_locked)
498+
_keymgr_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
472499
jl_unlock_profile();
473500
if (running) {
474501
// Reset the alarm

0 commit comments

Comments
 (0)