Skip to content

Commit

Permalink
make Profile more thread/signal-safe
Browse files Browse the repository at this point in the history
Fixes #35117
Fixes #13294
  • Loading branch information
vtjnash committed Aug 18, 2020
1 parent b514735 commit 180475f
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 58 deletions.
114 changes: 57 additions & 57 deletions src/debuginfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@

using namespace llvm;

using llvm_file_magic = file_magic;

#include "julia.h"
#include "julia_internal.h"
#include "debuginfo.h"
Expand Down Expand Up @@ -52,11 +50,37 @@ typedef object::SymbolRef SymRef;
// and cannot have any interaction with the julia runtime
static uv_rwlock_t threadsafe;

extern "C" void jl_init_debuginfo()
extern "C" void jl_init_debuginfo(void)
{
uv_rwlock_init(&threadsafe);
}

extern "C" void jl_lock_profile(void)
{
uv_rwlock_rdlock(&threadsafe);
}

extern "C" void jl_unlock_profile(void)
{
uv_rwlock_rdunlock(&threadsafe);
}

// some actions aren't signal (especially profiler) safe so we acquire a lock
// around them to establish a mutual exclusion with unwinding from a signal
template <typename T>
static void jl_profile_atomic(T f)
{
sigset_t sset;
sigset_t oset;
sigfillset(&sset);
uv_rwlock_wrlock(&threadsafe);
pthread_sigmask(SIG_BLOCK, &sset, &oset);
f();
pthread_sigmask(SIG_SETMASK, &oset, NULL);
uv_rwlock_wrunlock(&threadsafe);
}


// --- storing and accessing source location metadata ---

struct ObjectInfo {
Expand Down Expand Up @@ -278,7 +302,9 @@ class JuliaJITEventListener: public JITEventListener
di->u.rti.name_ptr = 0;
di->u.rti.table_data = arm_exidx_addr;
di->u.rti.table_len = arm_exidx_len;
_U_dyn_register(di);
jl_profile_atomic([&]() {
_U_dyn_register(di);
});
break;
}
#endif
Expand Down Expand Up @@ -431,14 +457,6 @@ class JuliaJITEventListener: public JITEventListener
uv_rwlock_rdlock(&threadsafe);
return objectmap;
}

Optional<std::map<size_t, ObjectInfo, revcomp>*> trygetObjectMap()
{
if (0 == uv_rwlock_tryrdlock(&threadsafe)) {
return &objectmap;
}
return {};
}
};

JL_DLLEXPORT void ORCNotifyObjectEmitted(JITEventListener *Listener,
Expand Down Expand Up @@ -482,7 +500,7 @@ static std::pair<char *, bool> jl_demangle(const char *name) JL_NOTSAFEPOINT
}

static JuliaJITEventListener *jl_jit_events;
JITEventListener *CreateJuliaJITEventListener()
JITEventListener *CreateJuliaJITEventListener(void)
{
jl_jit_events = new JuliaJITEventListener();
return jl_jit_events;
Expand Down Expand Up @@ -722,7 +740,7 @@ openDebugInfo(StringRef debuginfopath, const debug_link_info &info)

auto error_splitobj = object::ObjectFile::createObjectFile(
SplitFile.get().get()->getMemBufferRef(),
llvm_file_magic::unknown);
file_magic::unknown);
if (!error_splitobj) {
return error_splitobj.takeError();
}
Expand Down Expand Up @@ -873,7 +891,7 @@ static objfileentry_t &find_object_file(uint64_t fbase, StringRef fname) JL_NOTS
std::unique_ptr<MemoryBuffer> membuf = MemoryBuffer::getMemBuffer(
StringRef((const char *)fbase, msize), "", false);
auto origerrorobj = llvm::object::ObjectFile::createObjectFile(
membuf->getMemBufferRef(), llvm_file_magic::unknown);
membuf->getMemBufferRef(), file_magic::unknown);
if (!origerrorobj)
return entry;

Expand Down Expand Up @@ -1292,28 +1310,33 @@ void register_eh_frames(uint8_t *Addr, size_t Size)
// See http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-April/061768.html
processFDEs((char*)Addr, Size, [](const char *Entry) {
if (!libc_register_frame) {
libc_register_frame = (void(*)(void*))dlsym(RTLD_NEXT,"__register_frame");
libc_register_frame = (void(*)(void*))dlsym(RTLD_NEXT, "__register_frame");
}
assert(libc_register_frame);
libc_register_frame(const_cast<char *>(Entry));
__register_frame(const_cast<char *>(Entry));
jl_profile_atomic([&]() {
libc_register_frame(const_cast<char *>(Entry));
__register_frame(const_cast<char *>(Entry));
});
});
}

void deregister_eh_frames(uint8_t *Addr, size_t Size)
{
processFDEs((char*)Addr, Size, [](const char *Entry) {
if (!libc_deregister_frame) {
libc_deregister_frame = (void(*)(void*))dlsym(RTLD_NEXT,"__deregister_frame");
libc_deregister_frame = (void(*)(void*))dlsym(RTLD_NEXT, "__deregister_frame");
}
assert(libc_deregister_frame);
libc_deregister_frame(const_cast<char *>(Entry));
__deregister_frame(const_cast<char *>(Entry));
jl_profile_atomic([&]() {
libc_deregister_frame(const_cast<char *>(Entry));
__deregister_frame(const_cast<char *>(Entry));
});
});
}

#elif defined(_OS_LINUX_) && \
defined(JL_UNW_HAS_FORMAT_IP) && !defined(_CPU_ARM_)
defined(JL_UNW_HAS_FORMAT_IP) && \
!defined(_CPU_ARM_) // ARM does not have/use .eh_frame, so we handle this elsewhere
#include <type_traits>

struct unw_table_entry
Expand Down Expand Up @@ -1499,7 +1522,9 @@ static DW_EH_PE parseCIE(const uint8_t *Addr, const uint8_t *End)
void register_eh_frames(uint8_t *Addr, size_t Size)
{
// System unwinder
__register_frame(Addr);
jl_profile_atomic([&]() {
__register_frame(Addr);
});
// Our unwinder
unw_dyn_info_t *di = new unw_dyn_info_t;
// In a shared library, this is set to the address of the PLT.
Expand Down Expand Up @@ -1610,7 +1635,7 @@ void register_eh_frames(uint8_t *Addr, size_t Size)
start_ips[cur_entry] = start;
cur_entry++;
});
for (size_t i = 0;i < nentries;i++) {
for (size_t i = 0; i < nentries; i++) {
table[i].start_ip_offset =
safe_trunc<int32_t>((intptr_t)start_ips[i] - (intptr_t)start_ip);
}
Expand All @@ -1621,27 +1646,21 @@ void register_eh_frames(uint8_t *Addr, size_t Size)
di->start_ip = start_ip;
di->end_ip = end_ip;

_U_dyn_register(di);
jl_profile_atomic([&]() {
_U_dyn_register(di);
});
}

void deregister_eh_frames(uint8_t *Addr, size_t Size)
{
__deregister_frame(Addr);
// Deregistering with our unwinder requires a lookup table to find the
// the allocated entry above (or we could look in libunwind's internal
jl_profile_atomic([&]() {
__deregister_frame(Addr);
});
// Deregistering with our unwinder (_U_dyn_cancel) requires a lookup table
// to find the allocated entry above (or looking into libunwind's internal
// data structures).
}

#elif defined(_CPU_ARM_)

void register_eh_frames(uint8_t *Addr, size_t Size)
{
}

void deregister_eh_frames(uint8_t *Addr, size_t Size)
{
}

#else

void register_eh_frames(uint8_t *Addr, size_t Size)
Expand All @@ -1667,22 +1686,3 @@ uint64_t jl_getUnwindInfo(uint64_t dwAddr)
uv_rwlock_rdunlock(&threadsafe);
return ipstart;
}

extern "C"
uint64_t jl_trygetUnwindInfo(uint64_t dwAddr)
{
// Might be called from unmanaged thread
Optional<std::map<size_t, ObjectInfo, revcomp>*> maybeobjmap = jl_jit_events->trygetObjectMap();
if (maybeobjmap) {
std::map<size_t, ObjectInfo, revcomp> &objmap = **maybeobjmap;
std::map<size_t, ObjectInfo, revcomp>::iterator it = objmap.lower_bound(dwAddr);
uint64_t ipstart = 0; // ip of the start of the section (if found)
if (it != objmap.end() && dwAddr < it->first + it->second.SectionSize) {
ipstart = (uint64_t)(uintptr_t)(*it).first;
}
uv_rwlock_rdunlock(&threadsafe);
return ipstart;
}
return 0;
}

1 change: 0 additions & 1 deletion src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,6 @@ typedef struct {

// Might be called from unmanaged thread
uint64_t jl_getUnwindInfo(uint64_t dwBase);
uint64_t jl_trygetUnwindInfo(uint64_t dwBase);
#ifdef _OS_WINDOWS_
#include <dbghelp.h>
JL_DLLEXPORT EXCEPTION_DISPOSITION __julia_personality(
Expand Down
2 changes: 2 additions & 0 deletions src/signal-handling.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ static const uint64_t GIGA = 1000000000ULL;
// Timers to take samples at intervals
JL_DLLEXPORT void jl_profile_stop_timer(void);
JL_DLLEXPORT int jl_profile_start_timer(void);
void jl_lock_profile(void);
void jl_unlock_profile(void);

static uint64_t jl_last_sigint_trigger = 0;
static uint64_t jl_disable_sigint_time = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/signals-mach.c
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ void *mach_profile_listener(void *arg)
HANDLE_MACH_ERROR("mach_msg", ret);
// sample each thread, round-robin style in reverse order
// (so that thread zero gets notified last)
jl_lock_profile();
for (i = jl_n_threads; i-- > 0; ) {
// if there is no space left, break early
if (bt_size_cur >= bt_size_max - 1)
Expand Down Expand Up @@ -514,6 +515,7 @@ void *mach_profile_listener(void *arg)
// We're done! Resume the thread.
jl_thread_resume(i, 0);
}
jl_unlock_profile();
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/signals-unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,8 @@ static void *signal_listener(void *arg)
unw_context_t *signal_context;
// sample each thread, round-robin style in reverse order
// (so that thread zero gets notified last)
if (critical || profile)
jl_lock_profile();
for (int i = jl_n_threads; i-- > 0; ) {
// notify thread to stop
jl_thread_suspend_and_get_state(i, &signal_context);
Expand Down Expand Up @@ -717,6 +719,8 @@ static void *signal_listener(void *arg)
// notify thread to resume
jl_thread_resume(i, sig);
}
if (critical || profile)
jl_unlock_profile();
#endif

// this part is async with the running of the rest of the program
Expand Down
7 changes: 7 additions & 0 deletions src/signals-win.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,16 @@ HANDLE hMainThread = INVALID_HANDLE_VALUE;
static void jl_try_deliver_sigint(void)
{
jl_ptls_t ptls2 = jl_all_tls_states[0];
jl_lock_profile();
jl_safepoint_enable_sigint();
jl_wake_libuv();
if ((DWORD)-1 == SuspendThread(hMainThread)) {
// error
jl_safe_printf("error: SuspendThread failed\n");
jl_unlock_profile();
return;
}
jl_unlock_profile();
int force = jl_check_force_sigint();
if (force || (!ptls2->defer_signal && ptls2->io_wait)) {
jl_safepoint_consume_sigint();
Expand Down Expand Up @@ -338,8 +341,11 @@ static DWORD WINAPI profile_bt( LPVOID lparam )
timeout = min(max(timeout, tc.wPeriodMin*2), tc.wPeriodMax/2);
Sleep(timeout);
JL_LOCK_NOGC(&jl_in_stackwalk);
jl_lock_profile();
if ((DWORD)-1 == SuspendThread(hMainThread)) {
fputs("failed to suspend main thread. aborting profiling.", stderr);
jl_unlock_profile();
JL_UNLOCK_NOGC(&jl_in_stackwalk);
break;
}
if (running) {
Expand All @@ -357,6 +363,7 @@ static DWORD WINAPI profile_bt( LPVOID lparam )
if (bt_size_cur < bt_size_max)
bt_data_prof[bt_size_cur++].uintptr = 0;
}
jl_unlock_profile();
JL_UNLOCK_NOGC(&jl_in_stackwalk);
if ((DWORD)-1 == ResumeThread(hMainThread)) {
fputs("failed to resume main thread! aborting.", stderr);
Expand Down

0 comments on commit 180475f

Please sign in to comment.