Example #1
0
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
}
Example #2
0
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);
}
Example #3
0
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);
}
Example #4
0
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);
}
Example #5
0
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);
}