|
17 | 17 |
|
18 | 18 | #include "julia_assert.h"
|
19 | 19 |
|
| 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 | + |
20 | 32 | static void attach_exception_port(thread_port_t thread, int segv_only);
|
21 | 33 |
|
22 | 34 | // 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)
|
78 | 90 |
|
79 | 91 | static void allocate_segv_handler()
|
80 | 92 | {
|
| 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 | + |
81 | 104 | arraylist_new(&suspended_threads, jl_n_threads);
|
82 | 105 | pthread_t thread;
|
83 | 106 | pthread_attr_t attr;
|
@@ -421,6 +444,8 @@ void *mach_profile_listener(void *arg)
|
421 | 444 | // sample each thread, round-robin style in reverse order
|
422 | 445 | // (so that thread zero gets notified last)
|
423 | 446 | 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; |
424 | 449 | for (i = jl_n_threads; i-- > 0; ) {
|
425 | 450 | // if there is no space left, break early
|
426 | 451 | if (bt_size_cur >= bt_size_max - 1)
|
@@ -469,6 +494,8 @@ void *mach_profile_listener(void *arg)
|
469 | 494 | // We're done! Resume the thread.
|
470 | 495 | jl_thread_resume(i, 0);
|
471 | 496 | }
|
| 497 | + if (keymgr_locked) |
| 498 | + _keymgr_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); |
472 | 499 | jl_unlock_profile();
|
473 | 500 | if (running) {
|
474 | 501 | // Reset the alarm
|
|
0 commit comments