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.
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11 * See LICENSE for licensing information.
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #ifdef HAVE_SYS_TIME_H
26 #ifdef HAVE_SYS_SYSCALL_H
27 #include <sys/syscall.h>
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/loader.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/class.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/tokentype.h>
38 #include <mono/metadata/tabledefs.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/appdomain.h>
41 #include <mono/metadata/debug-helpers.h>
42 #include <mono/io-layer/io-layer.h>
43 #include "mono/metadata/profiler.h"
44 #include <mono/metadata/profiler-private.h>
45 #include <mono/metadata/mono-config.h>
46 #include <mono/metadata/environment.h>
47 #include <mono/metadata/mono-debug.h>
48 #include <mono/metadata/gc-internals.h>
49 #include <mono/metadata/threads-types.h>
50 #include <mono/metadata/verify.h>
51 #include <mono/metadata/verify-internals.h>
52 #include <mono/metadata/mempool-internals.h>
53 #include <mono/metadata/attach.h>
54 #include <mono/utils/mono-math.h>
55 #include <mono/utils/mono-compiler.h>
56 #include <mono/utils/mono-counters.h>
57 #include <mono/utils/mono-logger-internals.h>
58 #include <mono/utils/mono-mmap.h>
59 #include <mono/utils/dtrace.h>
60 #include <mono/utils/mono-signal-handler.h>
61 #include <mono/utils/mono-threads.h>
62 #include <mono/utils/mono-threads-posix-signals.h>
69 #include "debugger-agent.h"
71 #include "jit-icalls.h"
73 #ifdef PLATFORM_MACOSX
74 #include <mach/mach.h>
75 #include <mach/mach_time.h>
76 #include <mach/clock.h>
79 #if defined(__native_client__) || defined(HOST_WATCHOS)
82 mono_runtime_setup_stat_profiler (void)
84 printf("WARNING: mono_runtime_setup_stat_profiler() called!\n");
89 mono_runtime_shutdown_stat_profiler (void)
95 MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal
)
100 #ifndef PLATFORM_MACOSX
102 mono_runtime_install_handlers (void)
108 mono_runtime_posix_install_handlers(void)
110 /* we still need to ignore SIGPIPE */
111 signal (SIGPIPE
, SIG_IGN
);
115 mono_runtime_shutdown_handlers (void)
120 mono_runtime_cleanup_handlers (void)
124 #if !defined(PLATFORM_MACOSX)
126 mono_runtime_syscall_fork (void)
128 g_assert_not_reached();
133 mono_gdb_render_native_backtraces (pid_t crashed_pid
)
140 static GHashTable
*mono_saved_signal_handlers
= NULL
;
142 static struct sigaction
*
143 get_saved_signal_handler (int signo
, gboolean remove
)
145 if (mono_saved_signal_handlers
) {
146 /* The hash is only modified during startup, so no need for locking */
147 struct sigaction
*handler
= g_hash_table_lookup (mono_saved_signal_handlers
, GINT_TO_POINTER (signo
));
148 if (remove
&& handler
)
149 g_hash_table_remove (mono_saved_signal_handlers
, GINT_TO_POINTER (signo
));
156 save_old_signal_handler (int signo
, struct sigaction
*old_action
)
158 struct sigaction
*handler_to_save
= (struct sigaction
*)g_malloc (sizeof (struct sigaction
));
160 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_CONFIG
,
161 "Saving old signal handler for signal %d.", signo
);
163 if (! (old_action
->sa_flags
& SA_SIGINFO
)) {
164 handler_to_save
->sa_handler
= old_action
->sa_handler
;
166 #ifdef MONO_ARCH_USE_SIGACTION
167 handler_to_save
->sa_sigaction
= old_action
->sa_sigaction
;
168 #endif /* MONO_ARCH_USE_SIGACTION */
170 handler_to_save
->sa_mask
= old_action
->sa_mask
;
171 handler_to_save
->sa_flags
= old_action
->sa_flags
;
173 if (!mono_saved_signal_handlers
)
174 mono_saved_signal_handlers
= g_hash_table_new_full (NULL
, NULL
, NULL
, g_free
);
175 g_hash_table_insert (mono_saved_signal_handlers
, GINT_TO_POINTER (signo
), handler_to_save
);
179 free_saved_signal_handlers (void)
181 if (mono_saved_signal_handlers
) {
182 g_hash_table_destroy (mono_saved_signal_handlers
);
183 mono_saved_signal_handlers
= NULL
;
190 * Call the original signal handler for the signal given by the arguments, which
191 * should be the same as for a signal handler. Returns TRUE if the original handler
192 * was called, false otherwise.
195 MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal
)
197 int signal
= MONO_SIG_HANDLER_GET_SIGNO ();
198 struct sigaction
*saved_handler
= (struct sigaction
*)get_saved_signal_handler (signal
, FALSE
);
200 if (saved_handler
&& saved_handler
->sa_handler
) {
201 if (!(saved_handler
->sa_flags
& SA_SIGINFO
)) {
202 saved_handler
->sa_handler (signal
);
204 #ifdef MONO_ARCH_USE_SIGACTION
205 saved_handler
->sa_sigaction (MONO_SIG_HANDLER_PARAMS
);
206 #endif /* MONO_ARCH_USE_SIGACTION */
213 MONO_SIG_HANDLER_FUNC (static, sigabrt_signal_handler
)
215 MonoJitInfo
*ji
= NULL
;
216 MONO_SIG_HANDLER_INFO_TYPE
*info
= MONO_SIG_HANDLER_GET_INFO ();
217 MONO_SIG_HANDLER_GET_CONTEXT
;
219 if (mono_thread_internal_current ())
220 ji
= mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx
), TRUE
, TRUE
);
222 if (mono_chain_signal (MONO_SIG_HANDLER_PARAMS
))
224 mono_handle_native_sigsegv (SIGABRT
, ctx
, info
);
228 #if defined(__i386__) || defined(__x86_64__)
229 #define FULL_STAT_PROFILER_BACKTRACE 1
230 #define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f))
231 #define CURRENT_FRAME_GET_RETURN_ADDRESS(f) (* (((gpointer*)(f)) + 1))
232 #if MONO_ARCH_STACK_GROWS_UP
233 #define IS_BEFORE_ON_STACK <
234 #define IS_AFTER_ON_STACK >
236 #define IS_BEFORE_ON_STACK >
237 #define IS_AFTER_ON_STACK <
240 #define FULL_STAT_PROFILER_BACKTRACE 0
243 #if (defined (USE_POSIX_BACKEND) && defined (SIGRTMIN)) || defined (SIGPROF)
244 #define HAVE_PROFILER_SIGNAL
247 #ifdef HAVE_PROFILER_SIGNAL
250 per_thread_profiler_hit (void *ctx
)
252 int call_chain_depth
= mono_profiler_stat_get_call_chain_depth ();
253 MonoProfilerCallChainStrategy call_chain_strategy
= mono_profiler_stat_get_call_chain_strategy ();
255 if (call_chain_depth
== 0) {
256 mono_profiler_stat_hit ((guchar
*)mono_arch_ip_from_context (ctx
), ctx
);
258 MonoJitTlsData
*jit_tls
= (MonoJitTlsData
*)mono_native_tls_get_value (mono_jit_tls_id
);
259 int current_frame_index
= 1;
260 MonoContext mono_context
;
261 guchar
*ips
[call_chain_depth
+ 1];
263 mono_sigctx_to_monoctx (ctx
, &mono_context
);
264 ips
[0] = (guchar
*)MONO_CONTEXT_GET_IP (&mono_context
);
266 if (jit_tls
!= NULL
) {
267 if (call_chain_strategy
== MONO_PROFILER_CALL_CHAIN_NATIVE
) {
268 #if FULL_STAT_PROFILER_BACKTRACE
269 guchar
*current_frame
;
270 guchar
*stack_bottom
;
273 stack_bottom
= (guchar
*)jit_tls
->end_of_stack
;
274 stack_top
= (guchar
*)MONO_CONTEXT_GET_SP (&mono_context
);
275 current_frame
= (guchar
*)MONO_CONTEXT_GET_BP (&mono_context
);
277 while ((current_frame_index
<= call_chain_depth
) &&
278 (stack_bottom
IS_BEFORE_ON_STACK (guchar
*) current_frame
) &&
279 ((guchar
*) current_frame IS_BEFORE_ON_STACK stack_top
)) {
280 ips
[current_frame_index
] = (guchar
*)CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame
);
281 current_frame_index
++;
282 stack_top
= current_frame
;
283 current_frame
= (guchar
*)CURRENT_FRAME_GET_BASE_POINTER (current_frame
);
286 call_chain_strategy
= MONO_PROFILER_CALL_CHAIN_GLIBC
;
290 if (call_chain_strategy
== MONO_PROFILER_CALL_CHAIN_GLIBC
) {
291 #if GLIBC_PROFILER_BACKTRACE
292 current_frame_index
= backtrace ((void**) & ips
[1], call_chain_depth
);
294 call_chain_strategy
= MONO_PROFILER_CALL_CHAIN_MANAGED
;
298 if (call_chain_strategy
== MONO_PROFILER_CALL_CHAIN_MANAGED
) {
299 MonoDomain
*domain
= mono_domain_get ();
300 if (domain
!= NULL
) {
304 MonoContext new_mono_context
;
306 ji
= mono_find_jit_info (domain
, jit_tls
, &res
, NULL
, &mono_context
,
307 &new_mono_context
, NULL
, &lmf
, &native_offset
, NULL
);
308 while ((ji
!= NULL
) && (current_frame_index
<= call_chain_depth
)) {
309 ips
[current_frame_index
] = (guchar
*)MONO_CONTEXT_GET_IP (&new_mono_context
);
310 current_frame_index
++;
311 mono_context
= new_mono_context
;
312 ji
= mono_find_jit_info (domain
, jit_tls
, &res
, NULL
, &mono_context
,
313 &new_mono_context
, NULL
, &lmf
, &native_offset
, NULL
);
319 mono_profiler_stat_call_chain (current_frame_index
, & ips
[0], ctx
);
323 static MonoNativeThreadId sampling_thread
;
325 static gint32 profiler_signals_sent
;
326 static gint32 profiler_signals_received
;
327 static gint32 profiler_signals_accepted
;
328 static gint32 profiler_interrupt_signals_received
;
330 MONO_SIG_HANDLER_FUNC (static, profiler_signal_handler
)
332 int old_errno
= errno
;
334 MONO_SIG_HANDLER_GET_CONTEXT
;
336 /* See the comment in mono_runtime_shutdown_stat_profiler (). */
337 if (mono_native_thread_id_get () == sampling_thread
) {
338 #ifdef HAVE_CLOCK_NANOSLEEP
339 if (mono_profiler_get_sampling_mode () == MONO_PROFILER_STAT_MODE_PROCESS
) {
340 InterlockedIncrement (&profiler_interrupt_signals_received
);
345 g_error ("%s: Unexpected profiler signal received by the sampler thread", __func__
);
348 InterlockedIncrement (&profiler_signals_received
);
350 if (mono_thread_info_get_small_id () == -1)
351 return; //an non-attached thread got the signal
353 if (!mono_domain_get () || !mono_native_tls_get_value (mono_jit_tls_id
))
354 return; //thread in the process of dettaching
356 InterlockedIncrement (&profiler_signals_accepted
);
358 hp_save_index
= mono_hazard_pointer_save_for_signal_handler ();
360 mono_thread_info_set_is_async_context (TRUE
);
361 per_thread_profiler_hit (ctx
);
362 mono_thread_info_set_is_async_context (FALSE
);
364 mono_hazard_pointer_restore_for_signal_handler (hp_save_index
);
367 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
372 MONO_SIG_HANDLER_FUNC (static, sigquit_signal_handler
)
376 /* We use this signal to start the attach agent too */
377 res
= mono_attach_start ();
381 mono_threads_request_thread_dump ();
383 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
386 MONO_SIG_HANDLER_FUNC (static, sigusr2_signal_handler
)
388 gboolean enabled
= mono_trace_is_enabled ();
390 mono_trace_enable (!enabled
);
392 mono_chain_signal (MONO_SIG_HANDLER_PARAMS
);
396 add_signal_handler (int signo
, gpointer handler
, int flags
)
399 struct sigaction previous_sa
;
401 #ifdef MONO_ARCH_USE_SIGACTION
402 sa
.sa_sigaction
= (void (*)(int, siginfo_t
*, void *))handler
;
403 sigemptyset (&sa
.sa_mask
);
404 sa
.sa_flags
= SA_SIGINFO
| flags
;
405 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
407 /*Apple likes to deliver SIGBUS for *0 */
408 #ifdef PLATFORM_MACOSX
409 if (signo
== SIGSEGV
|| signo
== SIGBUS
) {
411 if (signo
== SIGSEGV
) {
413 sa
.sa_flags
|= SA_ONSTACK
;
416 * libgc will crash when trying to do stack marking for threads which are on
417 * an altstack, so delay the suspend signal after the signal handler has
420 if (mono_gc_get_suspend_signal () != -1)
421 sigaddset (&sa
.sa_mask
, mono_gc_get_suspend_signal ());
424 if (signo
== SIGSEGV
) {
426 * Delay abort signals while handling SIGSEGVs since they could go unnoticed.
430 sigemptyset (&block_mask
);
433 sa
.sa_handler
= handler
;
434 sigemptyset (&sa
.sa_mask
);
437 g_assert (sigaction (signo
, &sa
, &previous_sa
) != -1);
439 /* if there was already a handler in place for this signal, store it */
440 if (! (previous_sa
.sa_flags
& SA_SIGINFO
) &&
441 (SIG_DFL
== previous_sa
.sa_handler
)) {
442 /* it there is no sa_sigaction function and the sa_handler is default, we can safely ignore this */
444 if (mono_do_signal_chaining
)
445 save_old_signal_handler (signo
, &previous_sa
);
450 remove_signal_handler (int signo
)
453 struct sigaction
*saved_action
= get_saved_signal_handler (signo
, TRUE
);
456 sa
.sa_handler
= SIG_DFL
;
457 sigemptyset (&sa
.sa_mask
);
460 sigaction (signo
, &sa
, NULL
);
462 g_assert (sigaction (signo
, saved_action
, NULL
) != -1);
467 mono_runtime_posix_install_handlers (void)
472 if (mini_get_debug_options ()->handle_sigint
)
473 add_signal_handler (SIGINT
, mono_sigint_signal_handler
, SA_RESTART
);
475 add_signal_handler (SIGFPE
, mono_sigfpe_signal_handler
, 0);
476 add_signal_handler (SIGQUIT
, sigquit_signal_handler
, SA_RESTART
);
477 add_signal_handler (SIGILL
, mono_sigill_signal_handler
, 0);
478 add_signal_handler (SIGBUS
, mono_sigsegv_signal_handler
, 0);
479 if (mono_jit_trace_calls
!= NULL
)
480 add_signal_handler (SIGUSR2
, sigusr2_signal_handler
, SA_RESTART
);
482 /* it seems to have become a common bug for some programs that run as parents
483 * of many processes to block signal delivery for real time signals.
484 * We try to detect and work around their breakage here.
486 sigemptyset (&signal_set
);
487 if (mono_gc_get_suspend_signal () != -1)
488 sigaddset (&signal_set
, mono_gc_get_suspend_signal ());
489 if (mono_gc_get_restart_signal () != -1)
490 sigaddset (&signal_set
, mono_gc_get_restart_signal ());
491 sigaddset (&signal_set
, SIGCHLD
);
492 sigprocmask (SIG_UNBLOCK
, &signal_set
, NULL
);
494 signal (SIGPIPE
, SIG_IGN
);
496 add_signal_handler (SIGABRT
, sigabrt_signal_handler
, 0);
499 add_signal_handler (SIGSEGV
, mono_sigsegv_signal_handler
, 0);
502 #ifndef PLATFORM_MACOSX
504 mono_runtime_install_handlers (void)
506 mono_runtime_posix_install_handlers ();
511 mono_runtime_cleanup_handlers (void)
513 if (mini_get_debug_options ()->handle_sigint
)
514 remove_signal_handler (SIGINT
);
516 remove_signal_handler (SIGFPE
);
517 remove_signal_handler (SIGQUIT
);
518 remove_signal_handler (SIGILL
);
519 remove_signal_handler (SIGBUS
);
520 if (mono_jit_trace_calls
!= NULL
)
521 remove_signal_handler (SIGUSR2
);
523 remove_signal_handler (SIGABRT
);
525 remove_signal_handler (SIGSEGV
);
527 free_saved_signal_handlers ();
530 #ifdef HAVE_PROFILER_SIGNAL
532 static volatile gint32 sampling_thread_running
;
534 #ifdef PLATFORM_MACOSX
536 static clock_serv_t sampling_clock_service
;
544 ret
= host_get_clock_service (mach_host_self (), SYSTEM_CLOCK
, &sampling_clock_service
);
545 } while (ret
== KERN_ABORTED
);
547 if (ret
!= KERN_SUCCESS
)
548 g_error ("%s: host_get_clock_service () returned %d", __func__
, ret
);
557 ret
= mach_port_deallocate (mach_task_self (), sampling_clock_service
);
558 } while (ret
== KERN_ABORTED
);
560 if (ret
!= KERN_SUCCESS
)
561 g_error ("%s: mach_port_deallocate () returned %d", __func__
, ret
);
565 clock_get_time_ns (void)
568 mach_timespec_t mach_ts
;
571 ret
= clock_get_time (sampling_clock_service
, &mach_ts
);
572 } while (ret
== KERN_ABORTED
);
574 if (ret
!= KERN_SUCCESS
)
575 g_error ("%s: clock_get_time () returned %d", __func__
, ret
);
577 return ((guint64
) mach_ts
.tv_sec
* 1000000000) + (guint64
) mach_ts
.tv_nsec
;
581 clock_sleep_ns_abs (guint64 ns_abs
)
584 mach_timespec_t then
, remain_unused
;
586 then
.tv_sec
= ns_abs
/ 1000000000;
587 then
.tv_nsec
= ns_abs
% 1000000000;
590 ret
= clock_sleep (sampling_clock_service
, TIME_ABSOLUTE
, then
, &remain_unused
);
592 if (ret
!= KERN_SUCCESS
&& ret
!= KERN_ABORTED
)
593 g_error ("%s: clock_sleep () returned %d", __func__
, ret
);
594 } while (ret
== KERN_ABORTED
&& InterlockedRead (&sampling_thread_running
));
599 clockid_t sampling_posix_clock
;
604 switch (mono_profiler_get_sampling_mode ()) {
605 case MONO_PROFILER_STAT_MODE_PROCESS
:
606 #ifdef HAVE_CLOCK_NANOSLEEP
608 * If we don't have clock_nanosleep (), measuring the process time
609 * makes very little sense as we can only use nanosleep () to sleep on
612 sampling_posix_clock
= CLOCK_PROCESS_CPUTIME_ID
;
615 case MONO_PROFILER_STAT_MODE_REAL
: sampling_posix_clock
= CLOCK_MONOTONIC
; break;
616 default: g_assert_not_reached (); break;
626 clock_get_time_ns (void)
630 if (clock_gettime (sampling_posix_clock
, &ts
) == -1)
631 g_error ("%s: clock_gettime () returned -1, errno = %d", __func__
, errno
);
633 return ((guint64
) ts
.tv_sec
* 1000000000) + (guint64
) ts
.tv_nsec
;
637 clock_sleep_ns_abs (guint64 ns_abs
)
639 #ifdef HAVE_CLOCK_NANOSLEEP
641 struct timespec then
;
643 then
.tv_sec
= ns_abs
/ 1000000000;
644 then
.tv_nsec
= ns_abs
% 1000000000;
647 ret
= clock_nanosleep (sampling_posix_clock
, TIMER_ABSTIME
, &then
, NULL
);
649 if (ret
!= 0 && ret
!= EINTR
)
650 g_error ("%s: clock_nanosleep () returned %d", __func__
, ret
);
651 } while (ret
== EINTR
&& InterlockedRead (&sampling_thread_running
));
658 * What follows is a crude attempt at emulating clock_nanosleep () on OSs
659 * which don't provide it (e.g. FreeBSD).
661 * The problem with nanosleep () is that if it is interrupted by a signal,
662 * time will drift as a result of having to restart the call after the
663 * signal handler has finished. For this reason, we avoid using the rem
664 * argument of nanosleep (). Instead, before every nanosleep () call, we
665 * check if enough time has passed to satisfy the sleep request. If yes, we
666 * simply return. If not, we calculate the difference and do another sleep.
668 * This should reduce the amount of drift that happens because we account
669 * for the time spent executing the signal handler, which nanosleep () is
670 * not guaranteed to do for the rem argument.
672 * The downside to this approach is that it is slightly expensive: We have
673 * to make an extra system call to retrieve the current time whenever we're
674 * going to restart a nanosleep () call. This is unlikely to be a problem
675 * in practice since the sampling thread won't be receiving many signals in
676 * the first place (it's a tools thread, so no STW), and because typical
677 * sleep periods for the thread are many orders of magnitude bigger than
678 * the time it takes to actually perform that system call (just a few
682 diff
= (gint64
) ns_abs
- (gint64
) clock_get_time_ns ();
687 req
.tv_sec
= diff
/ 1000000000;
688 req
.tv_nsec
= diff
% 1000000000;
690 if ((ret
= nanosleep (&req
, NULL
)) == -1 && errno
!= EINTR
)
691 g_error ("%s: nanosleep () returned -1, errno = %d", __func__
, errno
);
692 } while (ret
== -1 && InterlockedRead (&sampling_thread_running
));
698 static int profiler_signal
;
699 static volatile gint32 sampling_thread_exiting
;
701 static mono_native_thread_return_t
702 sampling_thread_func (void *data
)
704 mono_threads_attach_tools_thread ();
705 mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler sampler");
707 gint64 rate
= 1000000000 / mono_profiler_get_sampling_rate ();
710 struct sched_param old_sched
;
711 pthread_getschedparam (pthread_self (), &old_policy
, &old_sched
);
714 * Attempt to switch the thread to real time scheduling. This will not
715 * necessarily work on all OSs; for example, most Linux systems will give
716 * us EPERM here unless configured to allow this.
718 * TODO: This does not work on Mac (and maybe some other OSs). On Mac, we
719 * have to use the Mach thread policy routines to switch to real-time
720 * scheduling. This is quite tricky as we need to specify how often we'll
721 * be doing work (easy), the normal processing time needed (also easy),
722 * and the maximum amount of processing time needed (hard). This is
723 * further complicated by the fact that if we misbehave and take too long
724 * to do our work, the kernel may knock us back down to the normal thread
725 * scheduling policy without telling us.
727 struct sched_param sched
= { .sched_priority
= sched_get_priority_max (SCHED_FIFO
) };
728 pthread_setschedparam (pthread_self (), SCHED_FIFO
, &sched
);
732 guint64 sleep
= clock_get_time_ns ();
734 while (InterlockedRead (&sampling_thread_running
)) {
737 FOREACH_THREAD_SAFE (info
) {
738 /* info should never be this thread as we're a tools thread. */
739 g_assert (mono_thread_info_get_tid (info
) != mono_native_thread_id_get ());
741 mono_threads_pthread_kill (info
, profiler_signal
);
742 InterlockedIncrement (&profiler_signals_sent
);
743 } FOREACH_THREAD_SAFE_END
745 clock_sleep_ns_abs (sleep
);
748 InterlockedWrite (&sampling_thread_exiting
, 1);
752 pthread_setschedparam (pthread_self (), old_policy
, &old_sched
);
754 mono_thread_info_detach ();
760 mono_runtime_shutdown_stat_profiler (void)
762 InterlockedWrite (&sampling_thread_running
, 0);
764 #ifdef HAVE_CLOCK_NANOSLEEP
766 * There is a slight problem when we're using CLOCK_PROCESS_CPUTIME_ID: If
767 * we're shutting down and there's largely no activity in the process other
768 * than waiting for the sampler thread to shut down, it can take upwards of
769 * 20 seconds (depending on a lot of factors) for us to shut down because
770 * the sleep progresses very slowly as a result of the low CPU activity.
772 * We fix this by repeatedly sending the profiler signal to the sampler
773 * thread in order to interrupt the sleep. clock_sleep_ns_abs () will check
774 * sampling_thread_running upon an interrupt and return immediately if it's
775 * zero. profiler_signal_handler () has a special case to ignore the signal
776 * for the sampler thread.
778 * We do not need to do this on platforms where we use a regular sleep
779 * based on a monotonic clock. The sleep will return in a reasonable amount
780 * of time in those cases.
782 if (mono_profiler_get_sampling_mode () == MONO_PROFILER_STAT_MODE_PROCESS
) {
783 MonoThreadInfo
*info
;
785 // Did it shut down already?
786 if ((info
= mono_thread_info_lookup (sampling_thread
))) {
787 while (!InterlockedRead (&sampling_thread_exiting
)) {
788 mono_threads_pthread_kill (info
, profiler_signal
);
789 mono_thread_info_usleep (10 * 1000 /* 10ms */);
792 // Make sure info can be freed.
793 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
798 pthread_join (sampling_thread
, NULL
);
801 * We can't safely remove the signal handler because we have no guarantee
802 * that all pending signals have been delivered at this point. This should
803 * not really be a problem anyway.
805 //remove_signal_handler (profiler_signal);
809 mono_runtime_setup_stat_profiler (void)
812 * Use a real-time signal when possible. This gives us roughly a 99% signal
813 * delivery rate in all cases. On the other hand, using a regular signal
814 * tends to result in awful delivery rates when the application is heavily
817 * We avoid real-time signals on Android as they're super broken in certain
818 * API levels (too small sigset_t, nonsensical SIGRTMIN/SIGRTMAX values,
821 * TODO: On Mac, we should explore using the Mach thread suspend/resume
822 * functions and doing the stack walk from the sampling thread. This would
823 * get us a 100% sampling rate. However, this may interfere with the GC's
824 * STW logic. Could perhaps be solved by taking the suspend lock.
826 #if defined (USE_POSIX_BACKEND) && defined (SIGRTMIN) && !defined (PLATFORM_ANDROID)
827 /* Just take the first real-time signal we can get. */
828 profiler_signal
= mono_threads_posix_signal_search_alternative (-1);
830 profiler_signal
= SIGPROF
;
833 add_signal_handler (profiler_signal
, profiler_signal_handler
, SA_RESTART
);
835 mono_counters_register ("Sampling signals sent", MONO_COUNTER_UINT
| MONO_COUNTER_PROFILER
| MONO_COUNTER_MONOTONIC
, &profiler_signals_sent
);
836 mono_counters_register ("Sampling signals received", MONO_COUNTER_UINT
| MONO_COUNTER_PROFILER
| MONO_COUNTER_MONOTONIC
, &profiler_signals_received
);
837 mono_counters_register ("Sampling signals accepted", MONO_COUNTER_UINT
| MONO_COUNTER_PROFILER
| MONO_COUNTER_MONOTONIC
, &profiler_signals_accepted
);
838 mono_counters_register ("Shutdown signals received", MONO_COUNTER_UINT
| MONO_COUNTER_PROFILER
| MONO_COUNTER_MONOTONIC
, &profiler_interrupt_signals_received
);
840 InterlockedWrite (&sampling_thread_running
, 1);
841 mono_native_thread_create (&sampling_thread
, sampling_thread_func
, NULL
);
847 mono_runtime_shutdown_stat_profiler (void)
852 mono_runtime_setup_stat_profiler (void)
858 #if !defined(PLATFORM_MACOSX)
860 mono_runtime_syscall_fork ()
862 #if defined(PLATFORM_ANDROID)
863 /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */
864 g_assert_not_reached ();
866 #elif defined(SYS_fork)
867 return (pid_t
) syscall (SYS_fork
);
869 g_assert_not_reached ();
875 mono_gdb_render_native_backtraces (pid_t crashed_pid
)
877 const char *argv
[9];
878 char template_
[] = "/tmp/mono-lldb-commands.XXXXXX";
881 gboolean using_lldb
= FALSE
;
883 argv
[0] = g_find_program_in_path ("gdb");
884 if (argv
[0] == NULL
) {
885 argv
[0] = g_find_program_in_path ("lldb");
889 if (argv
[0] == NULL
)
893 if (mkstemp (template_
) == -1)
896 commands
= fopen (template_
, "w");
898 fprintf (commands
, "process attach --pid %ld\n", (long) crashed_pid
);
899 fprintf (commands
, "thread list\n");
900 fprintf (commands
, "thread backtrace all\n");
901 fprintf (commands
, "detach\n");
902 fprintf (commands
, "quit\n");
907 argv
[1] = "--source";
908 argv
[2] = template_
;
912 sprintf (buf1
, "attach %ld", (long) crashed_pid
);
915 argv
[4] = "info threads";
917 argv
[6] = "thread apply all bt";
918 argv
[7] = "--batch";
922 execv (argv
[0], (char**)argv
);
928 #endif /* __native_client__ */
930 #if !defined (__MACH__)
933 mono_thread_state_init_from_handle (MonoThreadUnwindState
*tctx
, MonoThreadInfo
*info
)
935 g_error ("Posix systems don't support mono_thread_state_init_from_handle");