2 * mini-posix.c: POSIX signal handling support for Mono.
5 * Mono Team (mono-list@lists.ximian.com)
7 * Copyright 2001-2003 Ximian, Inc.
8 * Copyright 2003-2008 Ximian, Inc.
10 * See LICENSE for licensing information.
21 #ifdef HAVE_SYS_TIME_H
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/loader.h>
27 #include <mono/metadata/tabledefs.h>
28 #include <mono/metadata/class.h>
29 #include <mono/metadata/object.h>
30 #include <mono/metadata/tokentype.h>
31 #include <mono/metadata/tabledefs.h>
32 #include <mono/metadata/threads.h>
33 #include <mono/metadata/appdomain.h>
34 #include <mono/metadata/debug-helpers.h>
35 #include <mono/io-layer/io-layer.h>
36 #include "mono/metadata/profiler.h"
37 #include <mono/metadata/profiler-private.h>
38 #include <mono/metadata/mono-config.h>
39 #include <mono/metadata/environment.h>
40 #include <mono/metadata/mono-debug.h>
41 #include <mono/metadata/gc-internal.h>
42 #include <mono/metadata/threads-types.h>
43 #include <mono/metadata/verify.h>
44 #include <mono/metadata/verify-internals.h>
45 #include <mono/metadata/mempool-internals.h>
46 #include <mono/metadata/attach.h>
47 #include <mono/utils/mono-math.h>
48 #include <mono/utils/mono-compiler.h>
49 #include <mono/utils/mono-counters.h>
50 #include <mono/utils/mono-logger.h>
51 #include <mono/utils/mono-mmap.h>
52 #include <mono/utils/dtrace.h>
60 #include "jit-icalls.h"
62 static GHashTable
*mono_saved_signal_handlers
= NULL
;
65 get_saved_signal_handler (int signo
)
67 if (mono_saved_signal_handlers
)
68 /* The hash is only modified during startup, so no need for locking */
69 return g_hash_table_lookup (mono_saved_signal_handlers
, GINT_TO_POINTER (signo
));
74 save_old_signal_handler (int signo
, struct sigaction
*old_action
)
76 struct sigaction
*handler_to_save
= g_malloc (sizeof (struct sigaction
));
78 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_CONFIG
,
79 "Saving old signal handler for signal %d.", signo
);
81 if (! (old_action
->sa_flags
& SA_SIGINFO
)) {
82 handler_to_save
->sa_handler
= old_action
->sa_handler
;
84 #ifdef MONO_ARCH_USE_SIGACTION
85 handler_to_save
->sa_sigaction
= old_action
->sa_sigaction
;
86 #endif /* MONO_ARCH_USE_SIGACTION */
88 handler_to_save
->sa_mask
= old_action
->sa_mask
;
89 handler_to_save
->sa_flags
= old_action
->sa_flags
;
91 if (!mono_saved_signal_handlers
)
92 mono_saved_signal_handlers
= g_hash_table_new (NULL
, NULL
);
93 g_hash_table_insert (mono_saved_signal_handlers
, GINT_TO_POINTER (signo
), handler_to_save
);
97 free_saved_sig_handler_func (gpointer key
, gpointer value
, gpointer user_data
)
103 free_saved_signal_handlers (void)
105 if (mono_saved_signal_handlers
) {
106 g_hash_table_foreach (mono_saved_signal_handlers
, free_saved_sig_handler_func
, NULL
);
107 g_hash_table_destroy (mono_saved_signal_handlers
);
108 mono_saved_signal_handlers
= NULL
;
115 * Call the original signal handler for the signal given by the arguments, which
116 * should be the same as for a signal handler. Returns TRUE if the original handler
117 * was called, false otherwise.
120 SIG_HANDLER_SIGNATURE (mono_chain_signal
)
123 struct sigaction
*saved_handler
= get_saved_signal_handler (signal
);
128 if (!(saved_handler
->sa_flags
& SA_SIGINFO
)) {
129 saved_handler
->sa_handler (signal
);
131 #ifdef MONO_ARCH_USE_SIGACTION
132 saved_handler
->sa_sigaction (signal
, info
, ctx
);
133 #endif /* MONO_ARCH_USE_SIGACTION */
141 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler
)
146 ji
= mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx
));
148 if (mono_chain_signal (SIG_HANDLER_PARAMS
))
150 mono_handle_native_sigsegv (SIGABRT
, ctx
);
155 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler
)
157 gboolean running_managed
;
159 MonoThread
*thread
= mono_thread_current ();
160 MonoDomain
*domain
= mono_domain_get ();
165 if (!thread
|| !domain
)
166 /* The thread might not have started up yet */
167 /* FIXME: Specify the synchronization with start_wrapper () in threads.c */
170 if (thread
->thread_dump_requested
) {
171 thread
->thread_dump_requested
= FALSE
;
173 mono_print_thread_dump (ctx
);
178 * This is an async signal, so the code below must not call anything which
179 * is not async safe. That includes the pthread locking functions. If we
180 * know that we interrupted managed code, then locking is safe.
182 ji
= mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx
));
183 running_managed
= ji
!= NULL
;
185 exc
= mono_thread_request_interruption (running_managed
);
189 mono_arch_handle_exception (ctx
, exc
, FALSE
);
192 #if defined(__i386__) || defined(__x86_64__)
193 #define FULL_STAT_PROFILER_BACKTRACE 1
194 #define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f))
195 #define CURRENT_FRAME_GET_RETURN_ADDRESS(f) (* (((gpointer*)(f)) + 1))
196 #if MONO_ARCH_STACK_GROWS_UP
197 #define IS_BEFORE_ON_STACK <
198 #define IS_AFTER_ON_STACK >
200 #define IS_BEFORE_ON_STACK >
201 #define IS_AFTER_ON_STACK <
204 #define FULL_STAT_PROFILER_BACKTRACE 0
207 #if defined(__ia64__) || defined(__sparc__) || defined(sparc) || defined(__s390__) || defined(s390)
210 SIG_HANDLER_SIGNATURE (sigprof_signal_handler
)
212 if (mono_chain_signal (SIG_HANDLER_PARAMS
))
221 SIG_HANDLER_SIGNATURE (sigprof_signal_handler
)
223 int call_chain_depth
= mono_profiler_stat_get_call_chain_depth ();
226 if (call_chain_depth
== 0) {
227 mono_profiler_stat_hit (mono_arch_ip_from_context (ctx
), ctx
);
229 MonoJitTlsData
*jit_tls
= TlsGetValue (mono_jit_tls_id
);
230 int current_frame_index
= 1;
231 MonoContext mono_context
;
232 #if FULL_STAT_PROFILER_BACKTRACE
233 guchar
*current_frame
;
234 guchar
*stack_bottom
;
239 guchar
*ips
[call_chain_depth
+ 1];
241 mono_arch_sigctx_to_monoctx (ctx
, &mono_context
);
242 ips
[0] = MONO_CONTEXT_GET_IP (&mono_context
);
244 if (jit_tls
!= NULL
) {
245 #if FULL_STAT_PROFILER_BACKTRACE
246 stack_bottom
= jit_tls
->end_of_stack
;
247 stack_top
= MONO_CONTEXT_GET_SP (&mono_context
);
248 current_frame
= MONO_CONTEXT_GET_BP (&mono_context
);
250 while ((current_frame_index
<= call_chain_depth
) &&
251 (stack_bottom
IS_BEFORE_ON_STACK (guchar
*) current_frame
) &&
252 ((guchar
*) current_frame IS_BEFORE_ON_STACK stack_top
)) {
253 ips
[current_frame_index
] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame
);
254 current_frame_index
++;
255 stack_top
= current_frame
;
256 current_frame
= CURRENT_FRAME_GET_BASE_POINTER (current_frame
);
259 domain
= mono_domain_get ();
260 if (domain
!= NULL
) {
264 MonoContext new_mono_context
;
266 ji
= mono_find_jit_info (domain
, jit_tls
, &res
, NULL
, &mono_context
,
267 &new_mono_context
, NULL
, &lmf
, &native_offset
, NULL
);
268 while ((ji
!= NULL
) && (current_frame_index
<= call_chain_depth
)) {
269 ips
[current_frame_index
] = MONO_CONTEXT_GET_IP (&new_mono_context
);
270 current_frame_index
++;
271 mono_context
= new_mono_context
;
272 ji
= mono_find_jit_info (domain
, jit_tls
, &res
, NULL
, &mono_context
,
273 &new_mono_context
, NULL
, &lmf
, &native_offset
, NULL
);
279 mono_profiler_stat_call_chain (current_frame_index
, & ips
[0], ctx
);
282 mono_chain_signal (SIG_HANDLER_PARAMS
);
288 SIG_HANDLER_SIGNATURE (sigquit_signal_handler
)
294 /* We use this signal to start the attach agent too */
295 res
= mono_attach_start ();
299 printf ("Full thread dump:\n");
301 mono_threads_request_thread_dump ();
304 * print_thread_dump () skips the current thread, since sending a signal
305 * to it would invoke the signal handler below the sigquit signal handler,
306 * and signal handlers don't create an lmf, so the stack walk could not
309 mono_print_thread_dump (ctx
);
311 mono_chain_signal (SIG_HANDLER_PARAMS
);
315 SIG_HANDLER_SIGNATURE (sigusr2_signal_handler
)
317 gboolean enabled
= mono_trace_is_enabled ();
319 mono_trace_enable (!enabled
);
321 mono_chain_signal (SIG_HANDLER_PARAMS
);
325 add_signal_handler (int signo
, gpointer handler
)
328 struct sigaction previous_sa
;
330 #ifdef MONO_ARCH_USE_SIGACTION
331 sa
.sa_sigaction
= handler
;
332 sigemptyset (&sa
.sa_mask
);
333 sa
.sa_flags
= SA_SIGINFO
;
334 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
335 if (signo
== SIGSEGV
)
336 sa
.sa_flags
|= SA_ONSTACK
;
339 sa
.sa_handler
= handler
;
340 sigemptyset (&sa
.sa_mask
);
343 g_assert (sigaction (signo
, &sa
, &previous_sa
) != -1);
345 /* if there was already a handler in place for this signal, store it */
346 if (! (previous_sa
.sa_flags
& SA_SIGINFO
) &&
347 (SIG_DFL
== previous_sa
.sa_handler
)) {
348 /* it there is no sa_sigaction function and the sa_handler is default, we can safely ignore this */
350 if (mono_do_signal_chaining
)
351 save_old_signal_handler (signo
, &previous_sa
);
356 remove_signal_handler (int signo
)
359 struct sigaction
*saved_action
= get_saved_signal_handler (signo
);
362 sa
.sa_handler
= SIG_DFL
;
363 sigemptyset (&sa
.sa_mask
);
366 sigaction (signo
, &sa
, NULL
);
368 g_assert (sigaction (signo
, saved_action
, NULL
) != -1);
373 mono_runtime_posix_install_handlers (void)
378 if (mini_get_debug_options ()->handle_sigint
)
379 add_signal_handler (SIGINT
, mono_sigint_signal_handler
);
381 add_signal_handler (SIGFPE
, mono_sigfpe_signal_handler
);
382 add_signal_handler (SIGQUIT
, sigquit_signal_handler
);
383 add_signal_handler (SIGILL
, mono_sigill_signal_handler
);
384 add_signal_handler (SIGBUS
, mono_sigsegv_signal_handler
);
385 if (mono_jit_trace_calls
!= NULL
)
386 add_signal_handler (SIGUSR2
, sigusr2_signal_handler
);
388 add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler
);
389 /* it seems to have become a common bug for some programs that run as parents
390 * of many processes to block signal delivery for real time signals.
391 * We try to detect and work around their breakage here.
393 sigemptyset (&signal_set
);
394 sigaddset (&signal_set
, mono_thread_get_abort_signal ());
395 sigprocmask (SIG_UNBLOCK
, &signal_set
, NULL
);
397 signal (SIGPIPE
, SIG_IGN
);
399 add_signal_handler (SIGABRT
, sigabrt_signal_handler
);
402 add_signal_handler (SIGSEGV
, mono_sigsegv_signal_handler
);
405 #ifndef PLATFORM_MACOSX
407 mono_runtime_install_handlers (void)
409 mono_runtime_posix_install_handlers ();
414 mono_runtime_cleanup_handlers (void)
416 if (mini_get_debug_options ()->handle_sigint
)
417 remove_signal_handler (SIGINT
);
419 remove_signal_handler (SIGFPE
);
420 remove_signal_handler (SIGQUIT
);
421 remove_signal_handler (SIGILL
);
422 remove_signal_handler (SIGBUS
);
423 if (mono_jit_trace_calls
!= NULL
)
424 remove_signal_handler (SIGUSR2
);
426 remove_signal_handler (mono_thread_get_abort_signal ());
428 remove_signal_handler (SIGABRT
);
430 remove_signal_handler (SIGSEGV
);
432 free_saved_signal_handlers ();
435 #ifdef HAVE_LINUX_RTC_H
436 #include <linux/rtc.h>
437 #include <sys/ioctl.h>
439 static int rtc_fd
= -1;
442 enable_rtc_timer (gboolean enable
)
445 flags
= fcntl (rtc_fd
, F_GETFL
);
454 if (fcntl (rtc_fd
, F_SETFL
, flags
) == -1) {
463 mono_runtime_shutdown_stat_profiler (void)
465 #ifdef HAVE_LINUX_RTC_H
467 enable_rtc_timer (FALSE
);
472 mono_runtime_setup_stat_profiler (void)
475 struct itimerval itval
;
476 static int inited
= 0;
477 #ifdef HAVE_LINUX_RTC_H
478 const char *rtc_freq
;
479 if (!inited
&& (rtc_freq
= g_getenv ("MONO_RTC"))) {
483 freq
= atoi (rtc_freq
);
486 rtc_fd
= open ("/dev/rtc", O_RDONLY
);
488 perror ("open /dev/rtc");
491 add_signal_handler (SIGPROF
, sigprof_signal_handler
);
492 if (ioctl (rtc_fd
, RTC_IRQP_SET
, freq
) == -1) {
493 perror ("set rtc freq");
496 if (ioctl (rtc_fd
, RTC_PIE_ON
, 0) == -1) {
497 perror ("start rtc");
500 if (fcntl (rtc_fd
, F_SETSIG
, SIGPROF
) == -1) {
504 if (fcntl (rtc_fd
, F_SETOWN
, getpid ()) == -1) {
508 enable_rtc_timer (TRUE
);
515 itval
.it_interval
.tv_usec
= 999;
516 itval
.it_interval
.tv_sec
= 0;
517 itval
.it_value
= itval
.it_interval
;
518 setitimer (ITIMER_PROF
, &itval
, NULL
);
522 add_signal_handler (SIGPROF
, sigprof_signal_handler
);