/* * mini-posix.c: POSIX signal handling support for Mono. * * Authors: * Mono Team (mono-list@lists.ximian.com) * * Copyright 2001-2003 Ximian, Inc. * Copyright 2003-2008 Ximian, Inc. * * See LICENSE for licensing information. * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mono/metadata/profiler.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mini.h" #include #include #include "trace.h" #include "version.h" #include "jit-icalls.h" #ifdef _WIN32 #include #endif void mono_runtime_install_handlers (void) { #ifndef MONO_CROSS_COMPILE if (!mono_aot_only) { win32_seh_init(); win32_seh_set_handler(SIGFPE, mono_sigfpe_signal_handler); win32_seh_set_handler(SIGILL, mono_sigill_signal_handler); win32_seh_set_handler(SIGSEGV, mono_sigsegv_signal_handler); if (mini_get_debug_options ()->handle_sigint) win32_seh_set_handler(SIGINT, mono_sigint_signal_handler); } #endif } void mono_runtime_cleanup_handlers (void) { #ifndef MONO_CROSS_COMPILE if (!mono_aot_only) { win32_seh_cleanup(); } #endif } /* mono_chain_signal: * * Call the original signal handler for the signal given by the arguments, which * should be the same as for a signal handler. Returns TRUE if the original handler * was called, false otherwise. */ gboolean MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal) { MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); jit_tls->mono_win_chained_exception_needs_run = TRUE; return TRUE; } static HANDLE win32_main_thread; static MMRESULT win32_timer; static void CALLBACK win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { CONTEXT context; context.ContextFlags = CONTEXT_CONTROL; if (GetThreadContext (win32_main_thread, &context)) { #ifdef _WIN64 mono_profiler_stat_hit ((guchar *) context.Rip, &context); #else mono_profiler_stat_hit ((guchar *) context.Eip, &context); #endif } } void mono_runtime_setup_stat_profiler (void) { static int inited = 0; TIMECAPS timecaps; if (inited) return; inited = 1; if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR) return; if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL) return; if (timeBeginPeriod (1) != TIMERR_NOERROR) return; if ((win32_timer = timeSetEvent (1, 0, (LPTIMECALLBACK)win32_time_proc, (DWORD_PTR)NULL, TIME_PERIODIC)) == 0) { timeEndPeriod (1); return; } } void mono_runtime_shutdown_stat_profiler (void) { } gboolean mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info) { DWORD id = mono_thread_info_get_tid (info); HANDLE handle; CONTEXT context; DWORD result; MonoContext *ctx; MonoJitTlsData *jit_tls; void *domain; MonoLMF *lmf = NULL; gpointer *addr; tctx->valid = FALSE; tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = NULL; tctx->unwind_data [MONO_UNWIND_DATA_LMF] = NULL; tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = NULL; g_assert (id != GetCurrentThreadId ()); handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); g_assert (handle); context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; if (!GetThreadContext (handle, &context)) { CloseHandle (handle); return FALSE; } g_assert (context.ContextFlags & CONTEXT_INTEGER); g_assert (context.ContextFlags & CONTEXT_CONTROL); ctx = &tctx->ctx; memset (ctx, 0, sizeof (MonoContext)); mono_sigctx_to_monoctx (&context, ctx); /* mono_set_jit_tls () sets this */ jit_tls = mono_thread_info_tls_get (info, TLS_KEY_JIT_TLS); /* SET_APPDOMAIN () sets this */ domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN); /*Thread already started to cleanup, can no longer capture unwind state*/ if (!jit_tls || !domain) return FALSE; /* * The current LMF address is kept in a separate TLS variable, and its hard to read its value without * arch-specific code. But the address of the TLS variable is stored in another TLS variable which * can be accessed through MonoThreadInfo. */ /* mono_set_lmf_addr () sets this */ addr = mono_thread_info_tls_get (info, TLS_KEY_LMF_ADDR); if (addr) lmf = *addr; tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain; tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls; tctx->unwind_data [MONO_UNWIND_DATA_LMF] = lmf; tctx->valid = TRUE; return TRUE; }