diff --git a/configure.ac b/configure.ac index 427d37aa6975e..5785342780f0c 100644 --- a/configure.ac +++ b/configure.ac @@ -6681,6 +6681,7 @@ tools/Makefile tools/locale-builder/Makefile tools/sgen/Makefile tools/pedump/Makefile +tools/mono-hang-watchdog/Makefile runtime/Makefile msvc/Makefile po/Makefile diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index 490a342e0c2b7..b02e0821c056e 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -6262,7 +6262,6 @@ mono_threads_summarize_one (MonoThreadSummary *out, MonoContext *ctx) return success; } -#define TIMEOUT_CRASH_REPORTER_FATAL 30 #define MAX_NUM_THREADS 128 typedef struct { gint32 has_owner; // state of this memory @@ -6278,7 +6277,7 @@ typedef struct { gboolean silent; // print to stdout } SummarizerGlobalState; -#if defined(HAVE_KILL) && !defined(HOST_ANDROID) && defined(HAVE_WAITPID) && ((!defined(HOST_DARWIN) && defined(SYS_fork)) || HAVE_FORK) +#if defined(HAVE_KILL) && !defined(HOST_ANDROID) && defined(HAVE_WAITPID) && defined(HAVE_EXECVP) && ((!defined(HOST_DARWIN) && defined(SYS_fork)) || HAVE_FORK) #define HAVE_MONO_SUMMARIZER_SUPERVISOR 1 #endif @@ -6289,12 +6288,6 @@ typedef struct { } SummarizerSupervisorState; #ifndef HAVE_MONO_SUMMARIZER_SUPERVISOR -static void -summarizer_supervisor_wait (SummarizerSupervisorState *state) -{ - return; -} - static pid_t summarizer_supervisor_start (SummarizerSupervisorState *state) { @@ -6309,23 +6302,6 @@ summarizer_supervisor_end (SummarizerSupervisorState *state) } #else -static void -summarizer_supervisor_wait (SummarizerSupervisorState *state) -{ - sleep (TIMEOUT_CRASH_REPORTER_FATAL); - - // If we haven't been SIGKILL'ed yet, we signal our parent - // and then exit -#ifdef HAVE_KILL - g_async_safe_printf("Crash Reporter has timed out, sending SIGSEGV\n"); - kill (state->pid, SIGSEGV); -#else - g_error ("kill () is not supported by this platform"); -#endif - - exit (1); -} - static pid_t summarizer_supervisor_start (SummarizerSupervisorState *state) { @@ -6350,8 +6326,14 @@ summarizer_supervisor_start (SummarizerSupervisorState *state) g_assert_not_reached (); #endif - if (pid != 0) + if (pid != 0) { state->supervisor_pid = pid; + char pid_str[20]; // pid is a unit64_t, 20 digits max in decimal form + sprintf (pid_str, "%d", state->pid); + const char *const args[] = { "mono-hang-watchdog", pid_str }; + execvp (args[0], (char * const*)args); // run 'mono-hang-watchdog [pid]' + g_assert_not_reached (); + } return pid; } @@ -6665,8 +6647,6 @@ mono_threads_summarize (MonoContext *ctx, gchar **out, MonoStackHash *hashes, gb g_assert (mem); success = mono_threads_summarize_execute_internal (ctx, out, hashes, silent, mem, provided_size, TRUE); summarizer_supervisor_end (&synch); - } else { - summarizer_supervisor_wait (&synch); } if (!already_async) diff --git a/tools/Makefile.am b/tools/Makefile.am index 7a81089020092..831f7548310be 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = locale-builder sgen pedump +SUBDIRS = locale-builder sgen pedump mono-hang-watchdog diff --git a/tools/mono-hang-watchdog/Makefile.am b/tools/mono-hang-watchdog/Makefile.am new file mode 100644 index 0000000000000..8f823d87f59e2 --- /dev/null +++ b/tools/mono-hang-watchdog/Makefile.am @@ -0,0 +1,13 @@ + +AM_CPPFLAGS = $(SHARED_CFLAGS) + +if DISABLE_EXECUTABLES +bin_PROGRAMS = +else +bin_PROGRAMS = mono-hang-watchdog +endif + +CFLAGS = $(filter-out @CXX_REMOVE_CFLAGS@, @CFLAGS@) +mono_hang_watchdog_CFLAGS = @CXX_ADD_CFLAGS@ + +mono_hang_watchdog_SOURCES = mono-hang-watchdog.c diff --git a/tools/mono-hang-watchdog/mono-hang-watchdog.c b/tools/mono-hang-watchdog/mono-hang-watchdog.c new file mode 100644 index 0000000000000..d60feb2667690 --- /dev/null +++ b/tools/mono-hang-watchdog/mono-hang-watchdog.c @@ -0,0 +1,47 @@ +/* Given a external process' id as argument, the program waits for a set timeout then attempts to abort that process */ +/* Used by the Mono runtime's crash reporting. */ + +#include +#include +#include +#include + +#include "config.h" + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#ifndef HAVE_KILL +#error "kill() is not supported by this platform. This tool won't be able to function." +#endif + +#define TIMEOUT_CRASH_REPORTER_FATAL 30 + +static char* program_name; +void program_exit (int exit_code, const char* message); + +void program_exit (int exit_code, const char* message) { + if (message) + printf ("%s\n", message); + printf ("Usage: '%s [pid]'\t\t[pid]: The id for the Mono process\n", program_name); + exit (exit_code); +} + +int main (int argc, char* argv[]) +{ + program_name = argv[0]; + if (argc < 2) + program_exit (-1, "Please provide one argument (pid)"); + errno = 0; + pid_t pid = (pid_t)strtoul (argv[1], NULL, 10); + if (errno) + program_exit (-2, "Invalid pid"); + + sleep (TIMEOUT_CRASH_REPORTER_FATAL); + + /* Abort the process. This isn't suspect to 'pid' referring a wrong new process with the same id: + this process is killed by Mono if Mono doesn't hang */ + printf ("Mono hang watchdog timed out, sending SIGSEGV to %ul\n", pid); + kill (pid, SIGSEGV); +}