static void ti_initthread(int16_t tid) { jl_tls_states_t *ptls = jl_get_ptls_states(); #ifndef _OS_WINDOWS_ ptls->system_id = pthread_self(); #endif ptls->tid = tid; ptls->pgcstack = NULL; ptls->gc_state = 0; // GC unsafe // Conditionally initialize the safepoint address. See comment in // `safepoint.c` if (tid == 0) { ptls->safepoint = (size_t*)(jl_safepoint_pages + jl_page_size); } else { ptls->safepoint = (size_t*)(jl_safepoint_pages + jl_page_size * 2 + sizeof(size_t)); } ptls->defer_signal = 0; ptls->current_module = NULL; void *bt_data = malloc(sizeof(uintptr_t) * (JL_MAX_BT_SIZE + 1)); if (bt_data == NULL) { jl_printf(JL_STDERR, "could not allocate backtrace buffer\n"); gc_debug_critical_error(); abort(); } ptls->bt_data = (uintptr_t*)bt_data; jl_mk_thread_heap(ptls); jl_install_thread_signal_handler(); jl_all_tls_states[tid] = ptls; }
// what to do on a critical error void jl_critical_error(int sig, bt_context_t *context, uintptr_t *bt_data, size_t *bt_size) { // This function is not allowed to reference any TLS variables. // We need to explicitly pass in the TLS buffer pointer when // we make `jl_filename` and `jl_lineno` thread local. size_t i, n = *bt_size; if (sig) jl_safe_printf("\nsignal (%d): %s\n", sig, strsignal(sig)); jl_safe_printf("while loading %s, in expression starting on line %d\n", jl_filename, jl_lineno); if (context) *bt_size = n = rec_backtrace_ctx(bt_data, JL_MAX_BT_SIZE, context); for (i = 0; i < n; i++) jl_gdblookup(bt_data[i] - 1); gc_debug_print_status(); gc_debug_critical_error(); }
static DWORD WINAPI profile_bt( LPVOID lparam ) { // Note: illegal to use jl_* functions from this thread TIMECAPS tc; if (MMSYSERR_NOERROR!=timeGetDevCaps(&tc, sizeof(tc))) { fputs("failed to get timer resolution",stderr); hBtThread = 0; return 0; } while (1) { if (running && bt_size_cur < bt_size_max) { DWORD timeout = nsecprof/GIGA; timeout = min(max(timeout,tc.wPeriodMin*2),tc.wPeriodMax/2); Sleep(timeout); if ((DWORD)-1 == SuspendThread(hMainThread)) { fputs("failed to suspend main thread. aborting profiling.",stderr); break; } CONTEXT ctxThread; memset(&ctxThread, 0, sizeof(CONTEXT)); ctxThread.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; if (!GetThreadContext(hMainThread, &ctxThread)) { fputs("failed to get context from main thread. aborting profiling.",stderr); break; } // Get backtrace data bt_size_cur += rec_backtrace_ctx((uintptr_t*)bt_data_prof + bt_size_cur, bt_size_max - bt_size_cur - 1, &ctxThread); // Mark the end of this block with 0 bt_data_prof[bt_size_cur] = 0; bt_size_cur++; if ((DWORD)-1 == ResumeThread(hMainThread)) { fputs("failed to resume main thread! aborting.",stderr); gc_debug_critical_error(); abort(); } } else { SuspendThread(GetCurrentThread()); } } hBtThread = 0; return 0; }
void jl_safepoint_init(void) { // jl_page_size isn't available yet. size_t pgsz = jl_getpagesize(); #ifdef _OS_WINDOWS_ char *addr = (char*)VirtualAlloc(NULL, pgsz * 3, MEM_COMMIT, PAGE_READONLY); #else char *addr = (char*)mmap(0, pgsz * 3, PROT_READ, MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (addr == MAP_FAILED) addr = NULL; #endif if (addr == NULL) { jl_printf(JL_STDERR, "could not allocate GC synchronization page\n"); gc_debug_critical_error(); abort(); } // The signal page is for the gc safepoint. // The page before it is the sigint pending flag. jl_safepoint_pages = addr; }