diff --git a/doc/src/devdocs/locks.md b/doc/src/devdocs/locks.md index 8fa3fd4b6dc47e..7591f0df2d3566 100644 --- a/doc/src/devdocs/locks.md +++ b/doc/src/devdocs/locks.md @@ -27,6 +27,7 @@ The following are definitely leaf locks (level 1), and must not try to acquire a > * pagealloc > * gc_perm_lock > * flisp +> * jl_in_stackwalk (Win32) > > > flisp itself is already threadsafe, this lock only protects the `jl_ast_context_list_t` pool diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 46edf285d33f86..acf4b2c2240a44 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -108,8 +108,7 @@ static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnnam mod_size = Size; #endif if (0) { - assert(!jl_in_stackwalk); - jl_in_stackwalk = 1; + JL_LOCK_NOGC(&jl_in_stackwalk); if (mod_size && !SymLoadModuleEx(GetCurrentProcess(), NULL, NULL, NULL, (DWORD64)Section, mod_size, NULL, SLMFLAG_VIRTUAL)) { static int warned = 0; if (!warned) { @@ -129,7 +128,7 @@ static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnnam jl_printf(JL_STDERR, "WARNING: failed to insert function name %s into debug info: %lu\n", name, GetLastError()); } } - jl_in_stackwalk = 0; + JL_UNLOCK_NOGC(&jl_in_stackwalk); } #if defined(_CPU_X86_64_) if (!RtlAddFunctionTable(tbl, 1, (DWORD64)Section)) { @@ -832,12 +831,12 @@ static void get_function_name_and_base(llvm::object::SectionRef Section, size_t PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)frame_info_func; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); pSymbol->MaxNameLen = MAX_SYM_NAME; - jl_in_stackwalk = 1; + JL_LOCK_NOGC(&jl_in_stackwalk); if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement64, pSymbol)) { // errors are ignored jl_copy_str(name, pSymbol->Name); } - jl_in_stackwalk = 0; + JL_UNLOCK_NOGC(&jl_in_stackwalk); } #endif } @@ -1053,6 +1052,7 @@ static object::SectionRef getModuleSectionForAddress(const object::ObjectFile *o extern "C" void jl_refresh_dbg_module_list(void); + bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t *slide, llvm::DIContext **context, bool onlySysImg, bool *isSysImg, void **saddr, char **name, char **filename) JL_NOTSAFEPOINT { @@ -1077,11 +1077,12 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * #ifdef _OS_WINDOWS_ IMAGEHLP_MODULE64 ModuleInfo; ModuleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); + JL_LOCK_NOGC(&jl_in_stackwalk); jl_refresh_dbg_module_list(); - jl_in_stackwalk = 1; bool isvalid = SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)pointer, &ModuleInfo); - jl_in_stackwalk = 0; - if (!isvalid) return false; + JL_UNLOCK_NOGC(&jl_in_stackwalk); + if (!isvalid) + return false; StringRef fname = ModuleInfo.LoadedImageName; if (fname.empty()) // empirically, LoadedImageName might be missing @@ -1147,16 +1148,12 @@ bool jl_dylib_DI_for_fptr(size_t pointer, object::SectionRef *Section, int64_t * static int jl_getDylibFunctionInfo(jl_frame_t **frames, size_t pointer, int skipC, int noInline) JL_NOTSAFEPOINT { // This function is not allowed to reference any TLS variables if noInline - // since it can be called from an unmanaged thread on OSX. + // since it can be called from an unmanaged thread (the segfault handler) jl_frame_t *frame0 = *frames; #ifdef _OS_WINDOWS_ static IMAGEHLP_LINE64 frame_info_line; DWORD dwDisplacement = 0; - if (jl_in_stackwalk) { - frame0->fromC = 1; - return 1; - } - jl_in_stackwalk = 1; + JL_LOCK_NOGC(&jl_in_stackwalk); DWORD64 dwAddress = pointer; frame_info_line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); if (SymGetLineFromAddr64(GetCurrentProcess(), dwAddress, &dwDisplacement, &frame_info_line)) { @@ -1166,7 +1163,7 @@ static int jl_getDylibFunctionInfo(jl_frame_t **frames, size_t pointer, int skip jl_copy_str(&frame0->file_name, frame_info_line.FileName); frame0->line = frame_info_line.LineNumber; } - jl_in_stackwalk = 0; + JL_UNLOCK_NOGC(&jl_in_stackwalk); #endif object::SectionRef Section; llvm::DIContext *context = NULL; diff --git a/src/dlload.c b/src/dlload.c index ca60e9557fee5d..7359f07cc4610b 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -25,7 +25,7 @@ extern "C" { static char const *const extensions[] = { "", ".dylib" }; #elif defined(_OS_WINDOWS_) static char const *const extensions[] = { "", ".dll" }; -extern int needsSymRefreshModuleList; +extern volatile int needsSymRefreshModuleList; #else static char const *const extensions[] = { "", ".so" }; #endif @@ -92,12 +92,14 @@ static void win32_formatmessage(DWORD code, char *reason, int len) JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) { #if defined(_OS_WINDOWS_) - needsSymRefreshModuleList = 1; size_t len = MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); if (!len) return NULL; WCHAR *wfilename = (WCHAR*)alloca(len * sizeof(WCHAR)); if (!MultiByteToWideChar(CP_UTF8, 0, filename, -1, wfilename, len)) return NULL; - return LoadLibraryExW(wfilename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + HANDLE lib = LoadLibraryExW(wfilename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (lib) + needsSymRefreshModuleList = 1; + return lib; #else dlerror(); /* Reset error status. */ return dlopen(filename, diff --git a/src/init.c b/src/init.c index 42287b10e1bf32..2ccff9cdac3928 100644 --- a/src/init.c +++ b/src/init.c @@ -661,6 +661,7 @@ void _julia_init(JL_IMAGE_SEARCH rel) #endif jl_winsock_handle = jl_dlopen("ws2_32.dll", 0); jl_exe_handle = GetModuleHandleA(NULL); + JL_MUTEX_INIT(&jl_in_stackwalk); SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); if (!SymInitialize(GetCurrentProcess(), NULL, 1)) { jl_printf(JL_STDERR, "WARNING: failed to initialize stack walk info\n"); diff --git a/src/julia_internal.h b/src/julia_internal.h index 12ecbb9d28797d..5c2a0f22f943ca 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -771,7 +771,7 @@ typedef struct { CONTEXT context; } bt_cursor_t; #endif -extern volatile int jl_in_stackwalk; +extern jl_mutex_t jl_in_stackwalk; #elif !defined(JL_DISABLE_LIBUNWIND) // This gives unwind only local unwinding options ==> faster code # define UNW_LOCAL_ONLY @@ -793,7 +793,7 @@ size_t rec_backtrace(jl_bt_element_t *bt_data, size_t maxsize, int skip) JL_NOTS // Record backtrace from a signal handler. `ctx` is the context of the code // which was asynchronously interrupted. size_t rec_backtrace_ctx(jl_bt_element_t *bt_data, size_t maxsize, bt_context_t *ctx, - jl_gcframe_t *pgcstack, int lockless) JL_NOTSAFEPOINT; + jl_gcframe_t *pgcstack) JL_NOTSAFEPOINT; #ifdef LIBOSXUNWIND size_t rec_backtrace_ctx_dwarf(jl_bt_element_t *bt_data, size_t maxsize, bt_context_t *ctx, jl_gcframe_t *pgcstack) JL_NOTSAFEPOINT; #endif diff --git a/src/locks.h b/src/locks.h index b9d4d0a9d93a6b..77e428a23f6701 100644 --- a/src/locks.h +++ b/src/locks.h @@ -67,6 +67,7 @@ static inline void jl_lock_frame_push(jl_mutex_t *lock) static inline void jl_lock_frame_pop(void) { jl_ptls_t ptls = jl_get_ptls_states(); + assert(ptls->locks.len > 0); ptls->locks.len--; } diff --git a/src/signal-handling.c b/src/signal-handling.c index 759f143849c762..b17dbcecefc922 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -235,7 +235,7 @@ void jl_critical_error(int sig, bt_context_t *context, jl_bt_element_t *bt_data, if (context) { // Must avoid extended backtrace frames here unless we're sure bt_data // is properly rooted. - *bt_size = n = rec_backtrace_ctx(bt_data, JL_MAX_BT_SIZE, context, NULL, 1); + *bt_size = n = rec_backtrace_ctx(bt_data, JL_MAX_BT_SIZE, context, NULL); } for (i = 0; i < n; i += jl_bt_entry_size(bt_data + i)) { jl_print_bt_entry_codeloc(bt_data + i); diff --git a/src/signals-mach.c b/src/signals-mach.c index eafe30d590b1fe..2f04d25c5a5b75 100644 --- a/src/signals-mach.c +++ b/src/signals-mach.c @@ -164,7 +164,7 @@ static void jl_throw_in_thread(int tid, mach_port_t thread, jl_value_t *exceptio if (!ptls2->safe_restore) { assert(exception); ptls2->bt_size = rec_backtrace_ctx(ptls2->bt_data, JL_MAX_BT_SIZE, - (bt_context_t*)&state, ptls2->pgcstack, 0); + (bt_context_t*)&state, ptls2->pgcstack); ptls2->sig_exception = exception; } jl_call_in_state(ptls2, &state, &jl_sig_throw); @@ -490,7 +490,7 @@ void *mach_profile_listener(void *arg) if (forceDwarf == 0) { // Save the backtrace - bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)bt_data_prof + bt_size_cur, bt_size_max - bt_size_cur - 1, uc, NULL, 1); + bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)bt_data_prof + bt_size_cur, bt_size_max - bt_size_cur - 1, uc, NULL); } else if (forceDwarf == 1) { bt_size_cur += rec_backtrace_ctx_dwarf((jl_bt_element_t*)bt_data_prof + bt_size_cur, bt_size_max - bt_size_cur - 1, uc, NULL); diff --git a/src/signals-unix.c b/src/signals-unix.c index c3d93735d11680..dcf57ac54e51a6 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -184,7 +184,7 @@ static void jl_throw_in_ctx(jl_ptls_t ptls, jl_value_t *e, int sig, void *sigctx { if (!ptls->safe_restore) ptls->bt_size = rec_backtrace_ctx(ptls->bt_data, JL_MAX_BT_SIZE, - jl_to_bt_context(sigctx), ptls->pgcstack, 0); + jl_to_bt_context(sigctx), ptls->pgcstack); ptls->sig_exception = e; jl_call_in_ctx(ptls, &jl_sig_throw, sig, sigctx); } @@ -682,7 +682,7 @@ static void *signal_listener(void *arg) if (critical) { bt_size += rec_backtrace_ctx(bt_data + bt_size, JL_MAX_BT_SIZE / jl_n_threads - 1, - signal_context, NULL, 1); + signal_context, NULL); bt_data[bt_size++].uintptr = 0; } @@ -701,7 +701,7 @@ static void *signal_listener(void *arg) } else { // Get backtrace data bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)bt_data_prof + bt_size_cur, - bt_size_max - bt_size_cur - 1, signal_context, NULL, 1); + bt_size_max - bt_size_cur - 1, signal_context, NULL); } ptls->safe_restore = old_buf; diff --git a/src/signals-win.c b/src/signals-win.c index 09a8a546e43627..14bd250db5e4ef 100644 --- a/src/signals-win.c +++ b/src/signals-win.c @@ -96,15 +96,18 @@ void __cdecl crt_sig_handler(int sig, int num) } } +// StackOverflowException needs extra stack space to record the backtrace +// so we keep one around, shared by all threads +static jl_mutex_t backtrace_lock; static jl_ucontext_t collect_backtrace_fiber; static jl_ucontext_t error_return_fiber; -static PCONTEXT error_ctx; +static PCONTEXT stkerror_ctx; +static jl_ptls_t stkerror_ptls; static int have_backtrace_fiber; static void JL_NORETURN start_backtrace_fiber(void) { - jl_ptls_t ptls = jl_get_ptls_states(); // collect the backtrace - ptls->bt_size = rec_backtrace_ctx(ptls->bt_data, JL_MAX_BT_SIZE, error_ctx, ptls->pgcstack, 0); + stkerror_ptls->bt_size = rec_backtrace_ctx(stkerror_ptls->bt_data, JL_MAX_BT_SIZE, stkerror_ctx, stkerror_ptls->pgcstack); // switch back to the execution fiber jl_setcontext(&error_return_fiber); abort(); @@ -130,11 +133,14 @@ void jl_throw_in_ctx(jl_value_t *excpt, PCONTEXT ctxThread) assert(excpt != NULL); ptls->bt_size = 0; if (excpt != jl_stackovf_exception) { - ptls->bt_size = rec_backtrace_ctx(ptls->bt_data, JL_MAX_BT_SIZE, ctxThread, ptls->pgcstack, 0); + ptls->bt_size = rec_backtrace_ctx(ptls->bt_data, JL_MAX_BT_SIZE, ctxThread, ptls->pgcstack); } else if (have_backtrace_fiber) { - error_ctx = ctxThread; + JL_LOCK(&backtrace_lock); + stkerror_ctx = ctxThread; + stkerror_ptls = ptls; jl_swapcontext(&error_return_fiber, &collect_backtrace_fiber); + JL_UNLOCK_NOGC(&backtrace_lock); } ptls->sig_exception = excpt; } @@ -331,6 +337,7 @@ static DWORD WINAPI profile_bt( LPVOID lparam ) DWORD timeout = nsecprof/GIGA; timeout = min(max(timeout, tc.wPeriodMin*2), tc.wPeriodMax/2); Sleep(timeout); + JL_LOCK_NOGC(&jl_in_stackwalk); if ((DWORD)-1 == SuspendThread(hMainThread)) { fputs("failed to suspend main thread. aborting profiling.", stderr); break; @@ -345,11 +352,12 @@ static DWORD WINAPI profile_bt( LPVOID lparam ) } // Get backtrace data bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)bt_data_prof + bt_size_cur, - bt_size_max - bt_size_cur - 1, &ctxThread, NULL, 1); + bt_size_max - bt_size_cur - 1, &ctxThread, NULL); // Mark the end of this block with 0 - bt_data_prof[bt_size_cur].uintptr = 0; - bt_size_cur++; + if (bt_size_cur < bt_size_max) + bt_data_prof[bt_size_cur++].uintptr = 0; } + JL_UNLOCK_NOGC(&jl_in_stackwalk); if ((DWORD)-1 == ResumeThread(hMainThread)) { fputs("failed to resume main thread! aborting.", stderr); gc_debug_critical_error(); @@ -420,5 +428,6 @@ void jl_install_thread_signal_handler(jl_ptls_t ptls) collect_backtrace_fiber.uc_stack.ss_sp = (void*)stk; collect_backtrace_fiber.uc_stack.ss_size = ssize; jl_makecontext(&collect_backtrace_fiber, start_backtrace_fiber); + JL_MUTEX_INIT(&backtrace_lock); have_backtrace_fiber = 1; } diff --git a/src/stackwalk.c b/src/stackwalk.c index 7e003d429bc47f..f3ab648fe7ad91 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -13,6 +13,7 @@ // define `jl_unw_get` as a macro, since (like setjmp) // returning from the callee function will invalidate the context #ifdef _OS_WINDOWS_ +jl_mutex_t jl_in_stackwalk; #define jl_unw_get(context) RtlCaptureContext(context) #elif !defined(JL_DISABLE_LIBUNWIND) #define jl_unw_get(context) unw_getcontext(context) @@ -24,8 +25,8 @@ void jl_unw_get(void *context) {}; extern "C" { #endif -static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *context, int lockless) JL_NOTSAFEPOINT; -static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp, int lockless) JL_NOTSAFEPOINT; +static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *context) JL_NOTSAFEPOINT; +static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp) JL_NOTSAFEPOINT; static jl_gcframe_t *is_enter_interpreter_frame(jl_gcframe_t **ppgcstack, uintptr_t sp) JL_NOTSAFEPOINT { @@ -67,15 +68,14 @@ static jl_gcframe_t *is_enter_interpreter_frame(jl_gcframe_t **ppgcstack, uintpt // elements written to bt_data (and sp if non-NULL) are returned in bt_size. int jl_unw_stepn(bt_cursor_t *cursor, jl_bt_element_t *bt_data, size_t *bt_size, uintptr_t *sp, size_t maxsize, int skip, jl_gcframe_t **ppgcstack, - int from_signal_handler, int lockless) JL_NOTSAFEPOINT + int from_signal_handler) JL_NOTSAFEPOINT { volatile size_t n = 0; volatile int need_more_space = 0; uintptr_t return_ip = 0; uintptr_t thesp = 0; #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_) - assert(!jl_in_stackwalk); - jl_in_stackwalk = 1; + JL_LOCK_NOGC(&jl_in_stackwalk); if (!from_signal_handler) { // Workaround 32-bit windows bug missing top frame // See for example https://bugs.chromium.org/p/crashpad/issues/detail?id=53 @@ -96,7 +96,7 @@ int jl_unw_stepn(bt_cursor_t *cursor, jl_bt_element_t *bt_data, size_t *bt_size, need_more_space = 1; break; } - have_more_frames = jl_unw_step(cursor, &return_ip, &thesp, lockless); + have_more_frames = jl_unw_step(cursor, &return_ip, &thesp); if (skip > 0) { skip--; continue; @@ -172,20 +172,20 @@ int jl_unw_stepn(bt_cursor_t *cursor, jl_bt_element_t *bt_data, size_t *bt_size, ptls->safe_restore = old_buf; #endif #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_) - jl_in_stackwalk = 0; + JL_UNLOCK_NOGC(&jl_in_stackwalk); #endif *bt_size = n; return need_more_space; } NOINLINE size_t rec_backtrace_ctx(jl_bt_element_t *bt_data, size_t maxsize, - bt_context_t *context, jl_gcframe_t *pgcstack, int lockless) JL_NOTSAFEPOINT + bt_context_t *context, jl_gcframe_t *pgcstack) JL_NOTSAFEPOINT { bt_cursor_t cursor; - if (!jl_unw_init(&cursor, context, lockless)) + if (!jl_unw_init(&cursor, context)) return 0; size_t bt_size = 0; - jl_unw_stepn(&cursor, bt_data, &bt_size, NULL, maxsize, 0, &pgcstack, 1, lockless); + jl_unw_stepn(&cursor, bt_data, &bt_size, NULL, maxsize, 0, &pgcstack, 1); return bt_size; } @@ -201,10 +201,10 @@ NOINLINE size_t rec_backtrace(jl_bt_element_t *bt_data, size_t maxsize, int skip jl_unw_get(&context); jl_gcframe_t *pgcstack = jl_pgcstack; bt_cursor_t cursor; - if (!jl_unw_init(&cursor, &context, 0)) + if (!jl_unw_init(&cursor, &context)) return 0; size_t bt_size = 0; - jl_unw_stepn(&cursor, bt_data, &bt_size, NULL, maxsize, skip + 1, &pgcstack, 0, 0); + jl_unw_stepn(&cursor, bt_data, &bt_size, NULL, maxsize, skip + 1, &pgcstack, 0); return bt_size; } @@ -235,7 +235,7 @@ JL_DLLEXPORT jl_value_t *jl_backtrace_from_here(int returnsp, int skip) memset(&context, 0, sizeof(context)); jl_unw_get(&context); jl_gcframe_t *pgcstack = jl_pgcstack; - if (jl_unw_init(&cursor, &context, 0)) { + if (jl_unw_init(&cursor, &context)) { // Skip frame for jl_backtrace_from_here itself skip += 1; size_t offset = 0; @@ -249,7 +249,7 @@ JL_DLLEXPORT jl_value_t *jl_backtrace_from_here(int returnsp, int skip) } size_t size_incr = 0; have_more_frames = jl_unw_stepn(&cursor, (jl_bt_element_t*)jl_array_data(ip) + offset, - &size_incr, sp_ptr, maxincr, skip, &pgcstack, 0, 0); + &size_incr, sp_ptr, maxincr, skip, &pgcstack, 0); skip = 0; offset += size_incr; } @@ -374,13 +374,11 @@ static PVOID CALLBACK JuliaFunctionTableAccess64( #ifdef _CPU_X86_64_ DWORD64 ImageBase; PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(AddrBase, &ImageBase, &HistoryTable); - if (fn) return fn; - if (jl_in_stackwalk) { - return 0; - } - jl_in_stackwalk = 1; + if (fn) + return fn; + JL_LOCK_NOGC(&jl_in_stackwalk); PVOID ftable = SymFunctionTableAccess64(hProcess, AddrBase); - jl_in_stackwalk = 0; + JL_UNLOCK_NOGC(&jl_in_stackwalk); return ftable; #else return SymFunctionTableAccess64(hProcess, AddrBase); @@ -394,16 +392,15 @@ static DWORD64 WINAPI JuliaGetModuleBase64( #ifdef _CPU_X86_64_ DWORD64 ImageBase; PRUNTIME_FUNCTION fn = RtlLookupFunctionEntry(dwAddr, &ImageBase, &HistoryTable); - if (fn) return ImageBase; - if (jl_in_stackwalk) { - return 0; - } - jl_in_stackwalk = 1; + if (fn) + return ImageBase; + JL_LOCK_NOGC(&jl_in_stackwalk); DWORD64 fbase = SymGetModuleBase64(hProcess, dwAddr); - jl_in_stackwalk = 0; + JL_UNLOCK_NOGC(&jl_in_stackwalk); return fbase; #else - if (dwAddr == HistoryTable.dwAddr) return HistoryTable.ImageBase; + if (dwAddr == HistoryTable.dwAddr) + return HistoryTable.ImageBase; DWORD64 ImageBase = jl_getUnwindInfo(dwAddr); if (ImageBase) { HistoryTable.dwAddr = dwAddr; @@ -414,45 +411,23 @@ static DWORD64 WINAPI JuliaGetModuleBase64( #endif } -static DWORD64 WINAPI JuliaAsyncGetModuleBase64( - _In_ HANDLE hProcess, - _In_ DWORD64 dwAddr) -{ - //jl_printf(JL_STDOUT, "lookup base %d\n", dwAddr); -#ifdef _CPU_X86_64_ - return JuliaGetModuleBase64(hProcess, dwAddr); -#else - if (dwAddr == HistoryTable.dwAddr) return HistoryTable.ImageBase; - DWORD64 ImageBase = jl_trygetUnwindInfo(dwAddr); - if (ImageBase) { - HistoryTable.dwAddr = dwAddr; - HistoryTable.ImageBase = ImageBase; - return ImageBase; - } - return SymGetModuleBase64(hProcess, dwAddr); -#endif -} - // Might be called from unmanaged thread. -int needsSymRefreshModuleList; +volatile int needsSymRefreshModuleList; BOOL (WINAPI *hSymRefreshModuleList)(HANDLE); + void jl_refresh_dbg_module_list(void) { - if (needsSymRefreshModuleList && hSymRefreshModuleList != 0 && !jl_in_stackwalk) { - jl_in_stackwalk = 1; + if (needsSymRefreshModuleList && hSymRefreshModuleList != NULL) { hSymRefreshModuleList(GetCurrentProcess()); - jl_in_stackwalk = 0; needsSymRefreshModuleList = 0; } } -static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *Context, int lockless) +static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *Context) { + int result; + JL_LOCK_NOGC(&jl_in_stackwalk); jl_refresh_dbg_module_list(); #if !defined(_CPU_X86_64_) - if (jl_in_stackwalk) { - return 0; - } - jl_in_stackwalk = 1; memset(&cursor->stackframe, 0, sizeof(cursor->stackframe)); cursor->stackframe.AddrPC.Offset = Context->Eip; cursor->stackframe.AddrStack.Offset = Context->Esp; @@ -461,15 +436,15 @@ static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *Context, int lockless) cursor->stackframe.AddrStack.Mode = AddrModeFlat; cursor->stackframe.AddrFrame.Mode = AddrModeFlat; cursor->context = *Context; - BOOL result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread, - &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, - lockless ? JuliaAsyncGetModuleBase64 : JuliaGetModuleBase64, NULL); - jl_in_stackwalk = 0; - return result; + result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread, + &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, + JuliaGetModuleBase64, NULL); #else *cursor = *Context; - return 1; + result = 1; #endif + JL_UNLOCK_NOGC(&jl_in_stackwalk); + return result; } static int readable_pointer(LPCVOID pointer) @@ -486,10 +461,8 @@ static int readable_pointer(LPCVOID pointer) return 1; } -static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp, int lockless) +static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp) { - DWORD64 WINAPI (*GetModuleBase64)(HANDLE, DWORD64) = lockless ? - JuliaAsyncGetModuleBase64 : JuliaGetModuleBase64; // Might be called from unmanaged thread. #ifndef _CPU_X86_64_ *ip = (uintptr_t)cursor->stackframe.AddrPC.Offset; @@ -503,7 +476,7 @@ static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp, int lo } BOOL result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread, - &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, GetModuleBase64, NULL); + &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, JuliaGetModuleBase64, NULL); return result; #else *ip = (uintptr_t)cursor->Rip; @@ -516,7 +489,7 @@ static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp, int lo return cursor->Rip != 0; } - DWORD64 ImageBase = GetModuleBase64(GetCurrentProcess(), cursor->Rip); + DWORD64 ImageBase = JuliaGetModuleBase64(GetCurrentProcess(), cursor->Rip); if (!ImageBase) return 0; @@ -551,12 +524,12 @@ static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp, int lo #elif !defined(JL_DISABLE_LIBUNWIND) // stacktrace using libunwind -static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *context, int lockless) +static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *context) { return unw_init_local(cursor, context) == 0; } -static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp, int lockless) +static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp) { unw_word_t reg; if (unw_get_reg(cursor, UNW_REG_IP, ®) < 0) @@ -576,7 +549,7 @@ NOINLINE size_t rec_backtrace_ctx_dwarf(jl_bt_element_t *bt_data, size_t maxsize bt_cursor_t cursor; if (unw_init_local_dwarf(&cursor, context) != UNW_ESUCCESS) return 0; - jl_unw_stepn(&cursor, bt_data, &bt_size, NULL, maxsize, 0, &pgcstack, 1, 0); + jl_unw_stepn(&cursor, bt_data, &bt_size, NULL, maxsize, 0, &pgcstack, 1); return bt_size; } #endif @@ -588,7 +561,7 @@ static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *context) return 0; } -static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp, int lockless) +static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp) { return 0; } diff --git a/src/task.c b/src/task.c index 36f6bd0c5f39ee..e44981d0d62a86 100644 --- a/src/task.c +++ b/src/task.c @@ -67,9 +67,7 @@ static inline void tsan_destroy_ctx(jl_ptls_t ptls, jl_ucontext_t *ctx) {} static inline void tsan_switch_to_ctx(jl_ucontext_t *ctx) {} #endif -#if defined(_OS_WINDOWS_) -volatile int jl_in_stackwalk = 0; -#else +#if !defined(_OS_WINDOWS_) #ifdef JL_HAVE_UCONTEXT #include #endif