Skip to content

Commit fc97ae4

Browse files
committed
Backport of patch for #37101 to Julia 1.5.2 / for Julia 1.5.3.
1 parent cf8b9ec commit fc97ae4

File tree

9 files changed

+181
-106
lines changed

9 files changed

+181
-106
lines changed

base/process.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ Returns successfully if the process has already exited, but throws an
546546
error if killing the process failed for other reasons (e.g. insufficient
547547
permissions).
548548
"""
549-
function kill(p::Process, signum::Integer)
549+
function kill(p::Process, signum::Integer=SIGTERM)
550550
iolock_begin()
551551
if process_running(p)
552552
@assert p.handle != C_NULL
@@ -558,9 +558,8 @@ function kill(p::Process, signum::Integer)
558558
iolock_end()
559559
nothing
560560
end
561-
kill(ps::Vector{Process}) = foreach(kill, ps)
562-
kill(ps::ProcessChain) = foreach(kill, ps.processes)
563-
kill(p::Process) = kill(p, SIGTERM)
561+
kill(ps::Vector{Process}, signum::Integer=SIGTERM) = for p in ps; kill(p, signum); end
562+
kill(ps::ProcessChain, signum::Integer=SIGTERM) = kill(ps.processes, signum)
564563

565564
"""
566565
getpid(process) -> Int32

src/debuginfo.cpp

Lines changed: 83 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323

2424
using namespace llvm;
2525

26-
using llvm_file_magic = file_magic;
27-
2826
#include "julia.h"
2927
#include "julia_internal.h"
3028
#include "debuginfo.h"
@@ -55,11 +53,41 @@ typedef object::SymbolRef SymRef;
5553
// and cannot have any interaction with the julia runtime
5654
static uv_rwlock_t threadsafe;
5755

58-
extern "C" void jl_init_debuginfo()
56+
extern "C" void jl_init_debuginfo(void)
5957
{
6058
uv_rwlock_init(&threadsafe);
6159
}
6260

61+
extern "C" void jl_lock_profile(void)
62+
{
63+
uv_rwlock_rdlock(&threadsafe);
64+
}
65+
66+
extern "C" void jl_unlock_profile(void)
67+
{
68+
uv_rwlock_rdunlock(&threadsafe);
69+
}
70+
71+
// some actions aren't signal (especially profiler) safe so we acquire a lock
72+
// around them to establish a mutual exclusion with unwinding from a signal
73+
template <typename T>
74+
static void jl_profile_atomic(T f)
75+
{
76+
uv_rwlock_wrlock(&threadsafe);
77+
#ifndef _OS_WINDOWS_
78+
sigset_t sset;
79+
sigset_t oset;
80+
sigfillset(&sset);
81+
pthread_sigmask(SIG_BLOCK, &sset, &oset);
82+
#endif
83+
f();
84+
#ifndef _OS_WINDOWS_
85+
pthread_sigmask(SIG_SETMASK, &oset, NULL);
86+
#endif
87+
uv_rwlock_wrunlock(&threadsafe);
88+
}
89+
90+
6391
// --- storing and accessing source location metadata ---
6492

6593
struct ObjectInfo {
@@ -135,13 +163,15 @@ static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnnam
135163
jl_in_stackwalk = 0;
136164
}
137165
#if defined(_CPU_X86_64_)
138-
if (!RtlAddFunctionTable(tbl, 1, (DWORD64)Section)) {
139-
static int warned = 0;
140-
if (!warned) {
141-
jl_printf(JL_STDERR, "WARNING: failed to insert function stack unwind info: %lu\n", GetLastError());
142-
warned = 1;
166+
jl_profile_atomic([&]() {
167+
if (!RtlAddFunctionTable(tbl, 1, (DWORD64)Section)) {
168+
static int warned = 0;
169+
if (!warned) {
170+
jl_printf(JL_STDERR, "WARNING: failed to insert function stack unwind info: %lu\n", GetLastError());
171+
warned = 1;
172+
}
143173
}
144-
}
174+
});
145175
#endif
146176
}
147177
#endif
@@ -279,7 +309,9 @@ class JuliaJITEventListener: public JITEventListener
279309
di->u.rti.name_ptr = 0;
280310
di->u.rti.table_data = arm_exidx_addr;
281311
di->u.rti.table_len = arm_exidx_len;
282-
_U_dyn_register(di);
312+
jl_profile_atomic([&]() {
313+
_U_dyn_register(di);
314+
});
283315
break;
284316
}
285317
#endif
@@ -405,20 +437,20 @@ class JuliaJITEventListener: public JITEventListener
405437
codeinst = codeinst_it->second;
406438
codeinst_in_flight.erase(codeinst_it);
407439
}
408-
uv_rwlock_wrlock(&threadsafe);
409-
if (codeinst)
410-
linfomap[Addr] = std::make_pair(Size, codeinst->def);
411-
if (first) {
412-
ObjectInfo tmp = {&debugObj,
413-
(size_t)SectionSize,
414-
(ptrdiff_t)(SectionAddr - SectionLoadAddr),
415-
*Section,
416-
nullptr,
417-
};
418-
objectmap[SectionLoadAddr] = tmp;
419-
first = false;
420-
}
421-
uv_rwlock_wrunlock(&threadsafe);
440+
jl_profile_atomic([&]() {
441+
if (codeinst)
442+
linfomap[Addr] = std::make_pair(Size, codeinst->def);
443+
if (first) {
444+
ObjectInfo tmp = {&debugObj,
445+
(size_t)SectionSize,
446+
(ptrdiff_t)(SectionAddr - SectionLoadAddr),
447+
*Section,
448+
nullptr,
449+
};
450+
objectmap[SectionLoadAddr] = tmp;
451+
first = false;
452+
}
453+
});
422454
}
423455
jl_gc_safe_leave(ptls, gc_state);
424456
}
@@ -432,14 +464,6 @@ class JuliaJITEventListener: public JITEventListener
432464
uv_rwlock_rdlock(&threadsafe);
433465
return objectmap;
434466
}
435-
436-
Optional<std::map<size_t, ObjectInfo, revcomp>*> trygetObjectMap()
437-
{
438-
if (0 == uv_rwlock_tryrdlock(&threadsafe)) {
439-
return &objectmap;
440-
}
441-
return {};
442-
}
443467
};
444468

445469
JL_DLLEXPORT void ORCNotifyObjectEmitted(JITEventListener *Listener,
@@ -483,7 +507,7 @@ static std::pair<char *, bool> jl_demangle(const char *name) JL_NOTSAFEPOINT
483507
}
484508

485509
static JuliaJITEventListener *jl_jit_events;
486-
JITEventListener *CreateJuliaJITEventListener()
510+
JITEventListener *CreateJuliaJITEventListener(void)
487511
{
488512
jl_jit_events = new JuliaJITEventListener();
489513
return jl_jit_events;
@@ -723,7 +747,7 @@ openDebugInfo(StringRef debuginfopath, const debug_link_info &info)
723747

724748
auto error_splitobj = object::ObjectFile::createObjectFile(
725749
SplitFile.get().get()->getMemBufferRef(),
726-
llvm_file_magic::unknown);
750+
file_magic::unknown);
727751
if (!error_splitobj) {
728752
return error_splitobj.takeError();
729753
}
@@ -874,7 +898,7 @@ static objfileentry_t &find_object_file(uint64_t fbase, StringRef fname) JL_NOTS
874898
std::unique_ptr<MemoryBuffer> membuf = MemoryBuffer::getMemBuffer(
875899
StringRef((const char *)fbase, msize), "", false);
876900
auto origerrorobj = llvm::object::ObjectFile::createObjectFile(
877-
membuf->getMemBufferRef(), llvm_file_magic::unknown);
901+
membuf->getMemBufferRef(), file_magic::unknown);
878902
if (!origerrorobj)
879903
return entry;
880904

@@ -1295,28 +1319,33 @@ void register_eh_frames(uint8_t *Addr, size_t Size)
12951319
// See http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-April/061768.html
12961320
processFDEs((char*)Addr, Size, [](const char *Entry) {
12971321
if (!libc_register_frame) {
1298-
libc_register_frame = (void(*)(void*))dlsym(RTLD_NEXT,"__register_frame");
1322+
libc_register_frame = (void(*)(void*))dlsym(RTLD_NEXT, "__register_frame");
12991323
}
13001324
assert(libc_register_frame);
1301-
libc_register_frame(const_cast<char *>(Entry));
1302-
__register_frame(const_cast<char *>(Entry));
1325+
jl_profile_atomic([&]() {
1326+
libc_register_frame(const_cast<char *>(Entry));
1327+
__register_frame(const_cast<char *>(Entry));
1328+
});
13031329
});
13041330
}
13051331

13061332
void deregister_eh_frames(uint8_t *Addr, size_t Size)
13071333
{
13081334
processFDEs((char*)Addr, Size, [](const char *Entry) {
13091335
if (!libc_deregister_frame) {
1310-
libc_deregister_frame = (void(*)(void*))dlsym(RTLD_NEXT,"__deregister_frame");
1336+
libc_deregister_frame = (void(*)(void*))dlsym(RTLD_NEXT, "__deregister_frame");
13111337
}
13121338
assert(libc_deregister_frame);
1313-
libc_deregister_frame(const_cast<char *>(Entry));
1314-
__deregister_frame(const_cast<char *>(Entry));
1339+
jl_profile_atomic([&]() {
1340+
libc_deregister_frame(const_cast<char *>(Entry));
1341+
__deregister_frame(const_cast<char *>(Entry));
1342+
});
13151343
});
13161344
}
13171345

13181346
#elif defined(_OS_LINUX_) && \
1319-
defined(JL_UNW_HAS_FORMAT_IP) && !defined(_CPU_ARM_)
1347+
defined(JL_UNW_HAS_FORMAT_IP) && \
1348+
!defined(_CPU_ARM_) // ARM does not have/use .eh_frame, so we handle this elsewhere
13201349
#include <type_traits>
13211350

13221351
struct unw_table_entry
@@ -1502,7 +1531,9 @@ static DW_EH_PE parseCIE(const uint8_t *Addr, const uint8_t *End)
15021531
void register_eh_frames(uint8_t *Addr, size_t Size)
15031532
{
15041533
// System unwinder
1505-
__register_frame(Addr);
1534+
jl_profile_atomic([&]() {
1535+
__register_frame(Addr);
1536+
});
15061537
// Our unwinder
15071538
unw_dyn_info_t *di = new unw_dyn_info_t;
15081539
// In a shared library, this is set to the address of the PLT.
@@ -1613,7 +1644,7 @@ void register_eh_frames(uint8_t *Addr, size_t Size)
16131644
start_ips[cur_entry] = start;
16141645
cur_entry++;
16151646
});
1616-
for (size_t i = 0;i < nentries;i++) {
1647+
for (size_t i = 0; i < nentries; i++) {
16171648
table[i].start_ip_offset =
16181649
safe_trunc<int32_t>((intptr_t)start_ips[i] - (intptr_t)start_ip);
16191650
}
@@ -1624,27 +1655,21 @@ void register_eh_frames(uint8_t *Addr, size_t Size)
16241655
di->start_ip = start_ip;
16251656
di->end_ip = end_ip;
16261657

1627-
_U_dyn_register(di);
1658+
jl_profile_atomic([&]() {
1659+
_U_dyn_register(di);
1660+
});
16281661
}
16291662

16301663
void deregister_eh_frames(uint8_t *Addr, size_t Size)
16311664
{
1632-
__deregister_frame(Addr);
1633-
// Deregistering with our unwinder requires a lookup table to find the
1634-
// the allocated entry above (or we could look in libunwind's internal
1665+
jl_profile_atomic([&]() {
1666+
__deregister_frame(Addr);
1667+
});
1668+
// Deregistering with our unwinder (_U_dyn_cancel) requires a lookup table
1669+
// to find the allocated entry above (or looking into libunwind's internal
16351670
// data structures).
16361671
}
16371672

1638-
#elif defined(_CPU_ARM_)
1639-
1640-
void register_eh_frames(uint8_t *Addr, size_t Size)
1641-
{
1642-
}
1643-
1644-
void deregister_eh_frames(uint8_t *Addr, size_t Size)
1645-
{
1646-
}
1647-
16481673
#else
16491674

16501675
void register_eh_frames(uint8_t *Addr, size_t Size)
@@ -1670,22 +1695,3 @@ uint64_t jl_getUnwindInfo(uint64_t dwAddr)
16701695
uv_rwlock_rdunlock(&threadsafe);
16711696
return ipstart;
16721697
}
1673-
1674-
extern "C"
1675-
uint64_t jl_trygetUnwindInfo(uint64_t dwAddr)
1676-
{
1677-
// Might be called from unmanaged thread
1678-
Optional<std::map<size_t, ObjectInfo, revcomp>*> maybeobjmap = jl_jit_events->trygetObjectMap();
1679-
if (maybeobjmap) {
1680-
std::map<size_t, ObjectInfo, revcomp> &objmap = **maybeobjmap;
1681-
std::map<size_t, ObjectInfo, revcomp>::iterator it = objmap.lower_bound(dwAddr);
1682-
uint64_t ipstart = 0; // ip of the start of the section (if found)
1683-
if (it != objmap.end() && dwAddr < it->first + it->second.SectionSize) {
1684-
ipstart = (uint64_t)(uintptr_t)(*it).first;
1685-
}
1686-
uv_rwlock_rdunlock(&threadsafe);
1687-
return ipstart;
1688-
}
1689-
return 0;
1690-
}
1691-

src/julia_internal.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,6 @@ typedef struct {
758758

759759
// Might be called from unmanaged thread
760760
uint64_t jl_getUnwindInfo(uint64_t dwBase);
761-
uint64_t jl_trygetUnwindInfo(uint64_t dwBase);
762761
#ifdef _OS_WINDOWS_
763762
#include <dbghelp.h>
764763
JL_DLLEXPORT EXCEPTION_DISPOSITION __julia_personality(

src/signal-handling.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ static const uint64_t GIGA = 1000000000ULL;
2727
// Timers to take samples at intervals
2828
JL_DLLEXPORT void jl_profile_stop_timer(void);
2929
JL_DLLEXPORT int jl_profile_start_timer(void);
30+
void jl_lock_profile(void);
31+
void jl_unlock_profile(void);
3032

3133
static uint64_t jl_last_sigint_trigger = 0;
3234
static uint64_t jl_disable_sigint_time = 0;

src/signals-mach.c

Lines changed: 35 additions & 4 deletions
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;
@@ -420,6 +443,9 @@ void *mach_profile_listener(void *arg)
420443
HANDLE_MACH_ERROR("mach_msg", ret);
421444
// sample each thread, round-robin style in reverse order
422445
// (so that thread zero gets notified last)
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;
423449
for (i = jl_n_threads; i-- > 0; ) {
424450
// if there is no space left, break early
425451
if (bt_size_cur >= bt_size_max - 1)
@@ -464,14 +490,18 @@ void *mach_profile_listener(void *arg)
464490

465491
// Mark the end of this block with 0
466492
bt_data_prof[bt_size_cur++].uintptr = 0;
467-
468-
// Reset the alarm
469-
kern_return_t ret = clock_alarm(clk, TIME_RELATIVE, timerprof, profile_port);
470-
HANDLE_MACH_ERROR("clock_alarm", ret)
471493
}
472494
// We're done! Resume the thread.
473495
jl_thread_resume(i, 0);
474496
}
497+
if (keymgr_locked)
498+
_keymgr_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
499+
jl_unlock_profile();
500+
if (running) {
501+
// Reset the alarm
502+
kern_return_t ret = clock_alarm(clk, TIME_RELATIVE, timerprof, profile_port);
503+
HANDLE_MACH_ERROR("clock_alarm", ret)
504+
}
475505
}
476506
}
477507

@@ -505,6 +535,7 @@ JL_DLLEXPORT int jl_profile_start_timer(void)
505535
timerprof.tv_nsec = nsecprof%GIGA;
506536

507537
running = 1;
538+
// ensure the alarm is running
508539
ret = clock_alarm(clk, TIME_RELATIVE, timerprof, profile_port);
509540
HANDLE_MACH_ERROR("clock_alarm", ret);
510541

0 commit comments

Comments
 (0)