main: use SA_NODEFER to track signals to being able to raise from alarm

After we receive one of the tracked signals, in case we get stuck inside
the gjs_dumpstack () call, we use an alarm to raise the previously emitted
signal, however without using SA_NODEFER, the raise inside the alarm handler
will be ignored.

To avoid to handle new signals caused by the handler calls, once we get the
first signal, we just ignore them all as they could only lead to dirty traces.

Also, cleaning up a bit the code, and disabling the shell log handler
in dump_gjs_stack_alarm_sigaction since this might lead to a new
gjs_dumpstack () request.

https://bugzilla.gnome.org/show_bug.cgi?id=789237
This commit is contained in:
Marco Trevisan (Treviño) 2017-10-24 00:28:33 -05:00
parent f90b225eaa
commit 891bc45e36

View File

@ -48,6 +48,7 @@ enum {
SHELL_DEBUG_BACKTRACE_SEGFAULTS = 2, SHELL_DEBUG_BACKTRACE_SEGFAULTS = 2,
}; };
static int _shell_debug; static int _shell_debug;
static gboolean _tracked_signals[NSIG] = { 0 };
static void static void
shell_dbus_acquire_name (GDBusProxy *bus, shell_dbus_acquire_name (GDBusProxy *bus,
@ -332,11 +333,11 @@ shut_up (const char *domain,
} }
static void static void
dump_gjs_stack_alarm_sigaction (int signo, dump_gjs_stack_alarm_sigaction (int signo)
siginfo_t *info,
void *data)
{ {
g_log_set_default_handler (g_log_default_handler, NULL);
g_warning ("Failed to dump Javascript stack, got stuck"); g_warning ("Failed to dump Javascript stack, got stuck");
g_log_set_default_handler (default_log_handler, NULL);
raise (caught_signal); raise (caught_signal);
} }
@ -344,16 +345,24 @@ dump_gjs_stack_alarm_sigaction (int signo,
static void static void
dump_gjs_stack_on_signal_handler (int signo) dump_gjs_stack_on_signal_handler (int signo)
{ {
struct sigaction sa = { 0 };
gsize i;
/* Ignore all the signals starting this point, a part the one we'll raise
* (which is implicitly ignored here through SA_RESETHAND), this is needed
* not to get this handler being called by other signals that we were
* tracking and that might be emitted by code called starting from now.
*/
for (i = 0; i < G_N_ELEMENTS (_tracked_signals); ++i)
{
if (_tracked_signals[i] && i != signo)
signal (i, SIG_IGN);
}
/* Waiting at least 5 seconds for the dumpstack, if it fails, we raise the error */ /* Waiting at least 5 seconds for the dumpstack, if it fails, we raise the error */
struct sigaction sa;
caught_signal = signo; caught_signal = signo;
memset (&sa, 0, sizeof (sigaction)); sa.sa_handler = dump_gjs_stack_alarm_sigaction;
sigemptyset (&sa.sa_mask); sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = dump_gjs_stack_alarm_sigaction;
sigaction (SIGALRM, &sa, NULL); sigaction (SIGALRM, &sa, NULL);
alarm (5); alarm (5);
@ -366,15 +375,14 @@ dump_gjs_stack_on_signal_handler (int signo)
static void static void
dump_gjs_stack_on_signal (int signo) dump_gjs_stack_on_signal (int signo)
{ {
struct sigaction sa; struct sigaction sa = { 0 };
memset (&sa, 0, sizeof (sigaction)); sa.sa_flags = SA_RESETHAND | SA_NODEFER;
sa.sa_handler = dump_gjs_stack_on_signal_handler;
sigemptyset (&sa.sa_mask); sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_RESETHAND;
sa.sa_handler = dump_gjs_stack_on_signal_handler;
sigaction (signo, &sa, NULL); sigaction (signo, &sa, NULL);
_tracked_signals[signo] = TRUE;
} }
static gboolean static gboolean