void mono_runtime_setup_stat_profiler (void) { #ifdef ITIMER_PROF struct itimerval itval; static int inited = 0; #ifdef HAVE_LINUX_RTC_H const char *rtc_freq; if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) { int freq = 0; inited = 1; if (*rtc_freq) freq = atoi (rtc_freq); if (!freq) freq = 1024; rtc_fd = open ("/dev/rtc", O_RDONLY); if (rtc_fd == -1) { perror ("open /dev/rtc"); return; } add_signal_handler (SIGPROF, sigprof_signal_handler); if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) { perror ("set rtc freq"); return; } if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) { perror ("start rtc"); return; } if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) { perror ("setsig"); return; } if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) { perror ("setown"); return; } enable_rtc_timer (TRUE); return; } if (rtc_fd >= 0) return; #endif itval.it_interval.tv_usec = 999; itval.it_interval.tv_sec = 0; itval.it_value = itval.it_interval; setitimer (ITIMER_PROF, &itval, NULL); if (inited) return; inited = 1; add_signal_handler (SIGPROF, sigprof_signal_handler); #endif }
void mono_runtime_posix_install_handlers (void) { sigset_t signal_set; sigemptyset (&signal_set); if (mini_get_debug_options ()->handle_sigint) { add_signal_handler (SIGINT, mono_sigint_signal_handler, SA_RESTART); sigaddset (&signal_set, SIGINT); } add_signal_handler (SIGFPE, mono_sigfpe_signal_handler, 0); sigaddset (&signal_set, SIGFPE); add_signal_handler (SIGQUIT, sigquit_signal_handler, SA_RESTART); sigaddset (&signal_set, SIGQUIT); add_signal_handler (SIGILL, mono_sigill_signal_handler, 0); sigaddset (&signal_set, SIGILL); add_signal_handler (SIGBUS, mono_sigsegv_signal_handler, 0); sigaddset (&signal_set, SIGBUS); if (mono_jit_trace_calls != NULL) { add_signal_handler (SIGUSR2, sigusr2_signal_handler, SA_RESTART); sigaddset (&signal_set, SIGUSR2); } /* it seems to have become a common bug for some programs that run as parents * of many processes to block signal delivery for real time signals. * We try to detect and work around their breakage here. */ if (mono_gc_get_suspend_signal () != -1) sigaddset (&signal_set, mono_gc_get_suspend_signal ()); if (mono_gc_get_restart_signal () != -1) sigaddset (&signal_set, mono_gc_get_restart_signal ()); sigaddset (&signal_set, SIGCHLD); signal (SIGPIPE, SIG_IGN); sigaddset (&signal_set, SIGPIPE); add_signal_handler (SIGABRT, sigabrt_signal_handler, 0); sigaddset (&signal_set, SIGABRT); /* catch SIGSEGV */ add_signal_handler (SIGSEGV, mono_sigsegv_signal_handler, 0); sigaddset (&signal_set, SIGSEGV); sigprocmask (SIG_UNBLOCK, &signal_set, NULL); }
void mono_runtime_setup_stat_profiler (void) { /* * Use a real-time signal when possible. This gives us roughly a 99% signal * delivery rate in all cases. On the other hand, using a regular signal * tends to result in awful delivery rates when the application is heavily * loaded. * * We avoid real-time signals on Android as they're super broken in certain * API levels (too small sigset_t, nonsensical SIGRTMIN/SIGRTMAX values, * etc). * * TODO: On Mac, we should explore using the Mach thread suspend/resume * functions and doing the stack walk from the sampling thread. This would * get us a 100% sampling rate. However, this may interfere with the GC's * STW logic. Could perhaps be solved by taking the suspend lock. */ #if defined (USE_POSIX_BACKEND) && defined (SIGRTMIN) && !defined (HOST_ANDROID) /* Just take the first real-time signal we can get. */ profiler_signal = mono_threads_suspend_search_alternative_signal (); #else profiler_signal = SIGPROF; #endif add_signal_handler (profiler_signal, profiler_signal_handler, SA_RESTART); mono_counters_register ("Sampling signals sent", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &profiler_signals_sent); mono_counters_register ("Sampling signals received", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &profiler_signals_received); mono_counters_register ("Sampling signals accepted", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &profiler_signals_accepted); mono_counters_register ("Shutdown signals received", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &profiler_interrupt_signals_received); mono_os_event_init (&sampling_thread_exited, FALSE); mono_atomic_store_i32 (&sampling_thread_running, 1); MonoError error; MonoInternalThread *thread = mono_thread_create_internal (mono_get_root_domain (), sampling_thread_func, NULL, MONO_THREAD_CREATE_FLAGS_NONE, &error); mono_error_assert_ok (&error); sampling_thread = MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid); }
static void add_signal_handler (int signo, gpointer handler) { struct sigaction sa; struct sigaction previous_sa; #ifdef MONO_ARCH_USE_SIGACTION sa.sa_sigaction = handler; sigemptyset (&sa.sa_mask); sa.sa_flags = SA_SIGINFO; #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK /*Apple likes to deliver SIGBUS for *0 */ #ifdef __APPLE__ if (signo == SIGSEGV || signo == SIGBUS) { #else if (signo == SIGSEGV) { #endif sa.sa_flags |= SA_ONSTACK; /* * libgc will crash when trying to do stack marking for threads which are on * an altstack, so delay the suspend signal after the signal handler has * executed. */ if (mono_gc_get_suspend_signal () != -1) sigaddset (&sa.sa_mask, mono_gc_get_suspend_signal ()); } #endif if (signo == SIGSEGV) { /* * Delay abort signals while handling SIGSEGVs since they could go unnoticed. */ sigset_t block_mask; sigemptyset (&block_mask); sigaddset (&sa.sa_mask, mono_thread_get_abort_signal ()); } #else sa.sa_handler = handler; sigemptyset (&sa.sa_mask); sa.sa_flags = 0; #endif g_assert (sigaction (signo, &sa, &previous_sa) != -1); /* if there was already a handler in place for this signal, store it */ if (! (previous_sa.sa_flags & SA_SIGINFO) && (SIG_DFL == previous_sa.sa_handler)) { /* it there is no sa_sigaction function and the sa_handler is default, we can safely ignore this */ } else { if (mono_do_signal_chaining) save_old_signal_handler (signo, &previous_sa); } } static void remove_signal_handler (int signo) { struct sigaction sa; struct sigaction *saved_action = get_saved_signal_handler (signo); if (!saved_action) { sa.sa_handler = SIG_DFL; sigemptyset (&sa.sa_mask); sa.sa_flags = 0; sigaction (signo, &sa, NULL); } else { g_assert (sigaction (signo, saved_action, NULL) != -1); } } void mono_runtime_posix_install_handlers (void) { sigset_t signal_set; if (mini_get_debug_options ()->handle_sigint) add_signal_handler (SIGINT, mono_sigint_signal_handler); add_signal_handler (SIGFPE, mono_sigfpe_signal_handler); add_signal_handler (SIGQUIT, sigquit_signal_handler); add_signal_handler (SIGILL, mono_sigill_signal_handler); add_signal_handler (SIGBUS, mono_sigsegv_signal_handler); if (mono_jit_trace_calls != NULL) add_signal_handler (SIGUSR2, sigusr2_signal_handler); if (!mono_thread_info_new_interrupt_enabled ()) add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler); /* it seems to have become a common bug for some programs that run as parents * of many processes to block signal delivery for real time signals. * We try to detect and work around their breakage here. */ sigemptyset (&signal_set); sigaddset (&signal_set, mono_thread_get_abort_signal ()); sigprocmask (SIG_UNBLOCK, &signal_set, NULL); signal (SIGPIPE, SIG_IGN); add_signal_handler (SIGABRT, sigabrt_signal_handler); /* catch SIGSEGV */ add_signal_handler (SIGSEGV, mono_sigsegv_signal_handler); }
static void add_signal_handler (int signo, gpointer handler, int flags) { struct sigaction sa; struct sigaction previous_sa; #ifdef MONO_ARCH_USE_SIGACTION sa.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler; sigemptyset (&sa.sa_mask); sa.sa_flags = SA_SIGINFO | flags; #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK /*Apple likes to deliver SIGBUS for *0 */ #ifdef HOST_DARWIN if (signo == SIGSEGV || signo == SIGBUS) { #else if (signo == SIGSEGV) { #endif sa.sa_flags |= SA_ONSTACK; /* * libgc will crash when trying to do stack marking for threads which are on * an altstack, so delay the suspend signal after the signal handler has * executed. */ if (mono_gc_get_suspend_signal () != -1) sigaddset (&sa.sa_mask, mono_gc_get_suspend_signal ()); } #endif if (signo == SIGSEGV) { /* * Delay abort signals while handling SIGSEGVs since they could go unnoticed. */ sigset_t block_mask; sigemptyset (&block_mask); } #else sa.sa_handler = handler; sigemptyset (&sa.sa_mask); sa.sa_flags = flags; #endif g_assert (sigaction (signo, &sa, &previous_sa) != -1); /* if there was already a handler in place for this signal, store it */ if (! (previous_sa.sa_flags & SA_SIGINFO) && (SIG_DFL == previous_sa.sa_handler)) { /* it there is no sa_sigaction function and the sa_handler is default, we can safely ignore this */ } else { if (mono_do_signal_chaining) save_old_signal_handler (signo, &previous_sa); } } static void remove_signal_handler (int signo) { struct sigaction sa; struct sigaction *saved_action = get_saved_signal_handler (signo, TRUE); if (!saved_action) { sa.sa_handler = SIG_DFL; sigemptyset (&sa.sa_mask); sa.sa_flags = 0; sigaction (signo, &sa, NULL); } else { g_assert (sigaction (signo, saved_action, NULL) != -1); } } #ifdef TARGET_OSX void mini_register_sigterm_handler (void) { /* always catch SIGTERM, conditionals inside of handler */ add_signal_handler (SIGTERM, sigterm_signal_handler, 0); }