Commit 86e4b1ef authored by Michael Natterer's avatar Michael Natterer 😴 Committed by Michael Natterer

Another try to get the signal/dead child recovery stuff right.

2000-05-10  Michael Natterer  <mitch@gimp.org>

	Another try to get the signal/dead child recovery stuff right.

	Could the brave signal crew (TM) (Austin, Garry, Raphael, Tim)
	please do bad tests to the new code? I removed all strange
	constants (SA_NODEFER etc.) and used only glib and POSIX stuff.

	* app/main.c
	* libgimp/gimp.c:
	- Call gimp_signal_private() with no flags to enforce a proper
	  sigaction() behaviour (block signals while handler is active).
	- Removed the reentrancy guards from the handlers.
	- Renamed the handlers.
	- Ignore SIGPIPE in the app and in plugins.
	- Re-introduced the SIGCHLD handler because it should work
	  now. Also added a SIGCHLD handler to libgimp/gimp.c.

	* app/errors.c
	* libgimp/gimp.c: in the signal handler, unblock all signals
	with sigprocmask() before calling g_on_error_query() because
	gdb otherwise inherits the blocked signals and does nothing.
	Wrapped the statements with "if (TRUE) { }" blocks so it's
	easy to make the stack trace a command line option.

	* app/plug_in.c
	* libgimp/gimp.c: listen for G_IO_ERR and G_IO_HUP on the read
	channels. In the app, pop up an error message and clean up the
	plugin. In plugins, clean up and exit.

	* libgimp/gimpwire.c: removed the "plug-in chrashed?" message
	and print the program's name with all error messages.

	* plug-ins/helpbrowser/helpbrowser.c: typo.
parent 9879f8d3
2000-05-10 Michael Natterer <mitch@gimp.org>
Another try to get the signal/dead child recovery stuff right.
Could the brave signal crew (TM) (Austin, Garry, Raphael, Tim)
please do bad tests to the new code? I removed all strange
constants (SA_NODEFER etc.) and used only glib and POSIX stuff.
* app/main.c
* libgimp/gimp.c:
- Call gimp_signal_private() with no flags to enforce a proper
sigaction() behaviour (block signals while handler is active).
- Removed the reentrancy guards from the handlers.
- Renamed the handlers.
- Ignore SIGPIPE in the app and in plugins.
- Re-introduced the SIGCHLD handler because it should work
now. Also added a SIGCHLD handler to libgimp/gimp.c.
* app/errors.c
* libgimp/gimp.c: in the signal handler, unblock all signals
with sigprocmask() before calling g_on_error_query() because
gdb otherwise inherits the blocked signals and does nothing.
Wrapped the statements with "if (TRUE) { }" blocks so it's
easy to make the stack trace a command line option.
* app/plug_in.c
* libgimp/gimp.c: listen for G_IO_ERR and G_IO_HUP on the read
channels. In the app, pop up an error message and clean up the
plugin. In plugins, clean up and exit.
* libgimp/gimpwire.c: removed the "plug-in chrashed?" message
and print the program's name with all error messages.
* plug-ins/helpbrowser/helpbrowser.c: typo.
2000-05-10 Tor Lillqvist <tml@iki.fi>
* README.win32: Clarifications.
......
......@@ -338,13 +338,11 @@ plug_in_init (void)
}
/* insert the proc defs */
tmp = gimprc_proc_defs;
while (tmp)
for (tmp = gimprc_proc_defs; tmp; tmp = g_slist_next (tmp))
{
proc_def = g_new (PlugInProcDef, 1);
*proc_def = *((PlugInProcDef*) tmp->data);
plug_in_proc_def_insert (proc_def, NULL);
tmp = tmp->next;
}
tmp = plug_in_defs;
......@@ -408,11 +406,9 @@ plug_in_init (void)
g_print ("\n");
/* free up stuff */
tmp = plug_in_defs;
while (tmp)
for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp))
{
plug_in_def = tmp->data;
tmp = tmp->next;
plug_in_def_free (plug_in_def, FALSE);
}
......@@ -1033,10 +1029,11 @@ plug_in_open (PlugIn *plug_in)
if (!plug_in->synchronous)
{
plug_in->input_id = g_io_add_watch (plug_in->my_read,
G_IO_IN | G_IO_PRI,
plug_in_recv_message,
plug_in);
plug_in->input_id =
g_io_add_watch (plug_in->my_read,
G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
plug_in_recv_message,
plug_in);
open_plug_ins = g_slist_prepend (open_plug_ins, plug_in);
}
......@@ -1176,12 +1173,10 @@ plug_in_close (PlugIn *plug_in,
GSList *list;
PlugInProcDef *proc_def;
list = plug_in->temp_proc_defs;
while (list)
for (list = plug_in->temp_proc_defs; list; list = g_slist_next (list))
{
proc_def = (PlugInProcDef *) list->data;
plug_in_proc_def_remove (proc_def);
list = list->next;
}
g_slist_free (plug_in->temp_proc_defs);
......@@ -1189,9 +1184,9 @@ plug_in_close (PlugIn *plug_in,
}
/* Close any dialogs that this plugin might have opened */
brushes_check_dialogs();
patterns_check_dialogs();
gradients_check_dialogs();
brushes_check_dialogs ();
patterns_check_dialogs ();
gradients_check_dialogs ();
open_plug_ins = g_slist_remove (open_plug_ins, plug_in);
}
......@@ -1405,25 +1400,51 @@ plug_in_recv_message (GIOChannel *channel,
GIOCondition cond,
gpointer data)
{
WireMessage msg;
gboolean got_message = FALSE;
if ((PlugIn *) data != current_plug_in)
plug_in_push ((PlugIn *) data);
plug_in_push ((PlugIn*) data);
if (current_readchannel == NULL)
return TRUE;
memset (&msg, 0, sizeof (WireMessage));
if (!wire_read_msg (current_readchannel, &msg))
plug_in_close (current_plug_in, TRUE);
else
if (cond & (G_IO_IN | G_IO_PRI))
{
plug_in_handle_message (&msg);
wire_destroy (&msg);
WireMessage msg;
memset (&msg, 0, sizeof (WireMessage));
if (!wire_read_msg (current_readchannel, &msg))
{
plug_in_close (current_plug_in, TRUE);
}
else
{
plug_in_handle_message (&msg);
wire_destroy (&msg);
got_message = TRUE;
}
}
if (cond & (G_IO_ERR | G_IO_HUP))
{
if (current_plug_in->open)
{
plug_in_close (current_plug_in, TRUE);
}
}
if (!got_message)
g_message (_("Plug-In crashed: %s\n(%s)"),
g_basename (current_plug_in->args[0]),
current_plug_in->args[0]);
if (!current_plug_in->open)
plug_in_destroy (current_plug_in);
else
plug_in_pop ();
return TRUE;
}
......
......@@ -78,7 +78,14 @@ gimp_fatal_error (gchar *fmt, ...)
g_print ("%s: fatal error: %s\n", prog_name, g_strdup_vprintf (fmt, args));
va_end (args);
g_on_error_query (prog_name);
if (TRUE)
{
sigset_t sigset;
sigemptyset (&sigset);
sigprocmask (SIG_SETMASK, &sigset, NULL);
g_on_error_query (prog_name);
}
#else
/* g_on_error_query doesn't do anything reasonable on Win32. */
va_list args;
......@@ -106,7 +113,13 @@ gimp_terminate (gchar *fmt, ...)
va_end (args);
if (use_debug_handler)
g_on_error_query (prog_name);
{
sigset_t sigset;
sigemptyset (&sigset);
sigprocmask (SIG_SETMASK, &sigset, NULL);
g_on_error_query (prog_name);
}
#else
/* g_on_error_query doesn't do anything reasonable on Win32. */
va_list args;
......
......@@ -338,13 +338,11 @@ plug_in_init (void)
}
/* insert the proc defs */
tmp = gimprc_proc_defs;
while (tmp)
for (tmp = gimprc_proc_defs; tmp; tmp = g_slist_next (tmp))
{
proc_def = g_new (PlugInProcDef, 1);
*proc_def = *((PlugInProcDef*) tmp->data);
plug_in_proc_def_insert (proc_def, NULL);
tmp = tmp->next;
}
tmp = plug_in_defs;
......@@ -408,11 +406,9 @@ plug_in_init (void)
g_print ("\n");
/* free up stuff */
tmp = plug_in_defs;
while (tmp)
for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp))
{
plug_in_def = tmp->data;
tmp = tmp->next;
plug_in_def_free (plug_in_def, FALSE);
}
......@@ -1033,10 +1029,11 @@ plug_in_open (PlugIn *plug_in)
if (!plug_in->synchronous)
{
plug_in->input_id = g_io_add_watch (plug_in->my_read,
G_IO_IN | G_IO_PRI,
plug_in_recv_message,
plug_in);
plug_in->input_id =
g_io_add_watch (plug_in->my_read,
G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
plug_in_recv_message,
plug_in);
open_plug_ins = g_slist_prepend (open_plug_ins, plug_in);
}
......@@ -1176,12 +1173,10 @@ plug_in_close (PlugIn *plug_in,
GSList *list;
PlugInProcDef *proc_def;
list = plug_in->temp_proc_defs;
while (list)
for (list = plug_in->temp_proc_defs; list; list = g_slist_next (list))
{
proc_def = (PlugInProcDef *) list->data;
plug_in_proc_def_remove (proc_def);
list = list->next;
}
g_slist_free (plug_in->temp_proc_defs);
......@@ -1189,9 +1184,9 @@ plug_in_close (PlugIn *plug_in,
}
/* Close any dialogs that this plugin might have opened */
brushes_check_dialogs();
patterns_check_dialogs();
gradients_check_dialogs();
brushes_check_dialogs ();
patterns_check_dialogs ();
gradients_check_dialogs ();
open_plug_ins = g_slist_remove (open_plug_ins, plug_in);
}
......@@ -1405,25 +1400,51 @@ plug_in_recv_message (GIOChannel *channel,
GIOCondition cond,
gpointer data)
{
WireMessage msg;
gboolean got_message = FALSE;
if ((PlugIn *) data != current_plug_in)
plug_in_push ((PlugIn *) data);
plug_in_push ((PlugIn*) data);
if (current_readchannel == NULL)
return TRUE;
memset (&msg, 0, sizeof (WireMessage));
if (!wire_read_msg (current_readchannel, &msg))
plug_in_close (current_plug_in, TRUE);
else
if (cond & (G_IO_IN | G_IO_PRI))
{
plug_in_handle_message (&msg);
wire_destroy (&msg);
WireMessage msg;
memset (&msg, 0, sizeof (WireMessage));
if (!wire_read_msg (current_readchannel, &msg))
{
plug_in_close (current_plug_in, TRUE);
}
else
{
plug_in_handle_message (&msg);
wire_destroy (&msg);
got_message = TRUE;
}
}
if (cond & (G_IO_ERR | G_IO_HUP))
{
if (current_plug_in->open)
{
plug_in_close (current_plug_in, TRUE);
}
}
if (!got_message)
g_message (_("Plug-In crashed: %s\n(%s)"),
g_basename (current_plug_in->args[0]),
current_plug_in->args[0]);
if (!current_plug_in->open)
plug_in_destroy (current_plug_in);
else
plug_in_pop ();
return TRUE;
}
......
......@@ -338,13 +338,11 @@ plug_in_init (void)
}
/* insert the proc defs */
tmp = gimprc_proc_defs;
while (tmp)
for (tmp = gimprc_proc_defs; tmp; tmp = g_slist_next (tmp))
{
proc_def = g_new (PlugInProcDef, 1);
*proc_def = *((PlugInProcDef*) tmp->data);
plug_in_proc_def_insert (proc_def, NULL);
tmp = tmp->next;
}
tmp = plug_in_defs;
......@@ -408,11 +406,9 @@ plug_in_init (void)
g_print ("\n");
/* free up stuff */
tmp = plug_in_defs;
while (tmp)
for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp))
{
plug_in_def = tmp->data;
tmp = tmp->next;
plug_in_def_free (plug_in_def, FALSE);
}
......@@ -1033,10 +1029,11 @@ plug_in_open (PlugIn *plug_in)
if (!plug_in->synchronous)
{
plug_in->input_id = g_io_add_watch (plug_in->my_read,
G_IO_IN | G_IO_PRI,
plug_in_recv_message,
plug_in);
plug_in->input_id =
g_io_add_watch (plug_in->my_read,
G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
plug_in_recv_message,
plug_in);
open_plug_ins = g_slist_prepend (open_plug_ins, plug_in);
}
......@@ -1176,12 +1173,10 @@ plug_in_close (PlugIn *plug_in,
GSList *list;
PlugInProcDef *proc_def;
list = plug_in->temp_proc_defs;
while (list)
for (list = plug_in->temp_proc_defs; list; list = g_slist_next (list))
{
proc_def = (PlugInProcDef *) list->data;
plug_in_proc_def_remove (proc_def);
list = list->next;
}
g_slist_free (plug_in->temp_proc_defs);
......@@ -1189,9 +1184,9 @@ plug_in_close (PlugIn *plug_in,
}
/* Close any dialogs that this plugin might have opened */
brushes_check_dialogs();
patterns_check_dialogs();
gradients_check_dialogs();
brushes_check_dialogs ();
patterns_check_dialogs ();
gradients_check_dialogs ();
open_plug_ins = g_slist_remove (open_plug_ins, plug_in);
}
......@@ -1405,25 +1400,51 @@ plug_in_recv_message (GIOChannel *channel,
GIOCondition cond,
gpointer data)
{
WireMessage msg;
gboolean got_message = FALSE;
if ((PlugIn *) data != current_plug_in)
plug_in_push ((PlugIn *) data);
plug_in_push ((PlugIn*) data);
if (current_readchannel == NULL)
return TRUE;
memset (&msg, 0, sizeof (WireMessage));
if (!wire_read_msg (current_readchannel, &msg))
plug_in_close (current_plug_in, TRUE);
else
if (cond & (G_IO_IN | G_IO_PRI))
{
plug_in_handle_message (&msg);
wire_destroy (&msg);
WireMessage msg;
memset (&msg, 0, sizeof (WireMessage));
if (!wire_read_msg (current_readchannel, &msg))
{
plug_in_close (current_plug_in, TRUE);
}
else
{
plug_in_handle_message (&msg);
wire_destroy (&msg);
got_message = TRUE;
}
}
if (cond & (G_IO_ERR | G_IO_HUP))
{
if (current_plug_in->open)
{
plug_in_close (current_plug_in, TRUE);
}
}
if (!got_message)
g_message (_("Plug-In crashed: %s\n(%s)"),
g_basename (current_plug_in->args[0]),
current_plug_in->args[0]);
if (!current_plug_in->open)
plug_in_destroy (current_plug_in);
else
plug_in_pop ();
return TRUE;
}
......
......@@ -54,14 +54,15 @@
#ifdef G_OS_WIN32
#include <windows.h>
#else
static void on_signal (gint);
static void gimp_sigfatal_handler (gint sig_num);
static void gimp_sigchld_handler (gint sig_num);
#endif
static void init (void);
static void on_error (const gchar *domain,
GLogLevelFlags flags,
const gchar *msg,
gpointer user_data);
static void init (void);
static void gimp_error_handler (const gchar *domain,
GLogLevelFlags flags,
const gchar *msg,
gpointer user_data);
/* GLOBAL data */
gboolean no_interface = FALSE;
......@@ -327,37 +328,36 @@ main (int argc,
/* No use catching these on Win32, the user won't get any
* stack trace from glib anyhow. It's better to let Windows inform
* about the program error, and offer debugging (if the use
* about the program error, and offer debugging (if the user
* has installed MSVC or some other compiler that knows how to
* install itself as a handler for program errors).
*/
/* Handle some signals */
/* Handle fatal signals */
gimp_signal_private (SIGHUP, on_signal, SA_RESETHAND | SA_NODEFER);
gimp_signal_private (SIGINT, on_signal, SA_RESETHAND | SA_NODEFER);
gimp_signal_private (SIGQUIT, on_signal, SA_RESETHAND | SA_NODEFER);
gimp_signal_private (SIGABRT, on_signal, SA_RESETHAND | SA_NODEFER);
gimp_signal_private (SIGBUS, on_signal, SA_RESETHAND | SA_NODEFER);
gimp_signal_private (SIGSEGV, on_signal, SA_RESETHAND | SA_NODEFER);
gimp_signal_private (SIGPIPE, on_signal, SA_RESETHAND | SA_NODEFER);
gimp_signal_private (SIGTERM, on_signal, SA_RESETHAND | SA_NODEFER);
gimp_signal_private (SIGFPE, on_signal, SA_RESETHAND | SA_NODEFER);
gimp_signal_private (SIGHUP, gimp_sigfatal_handler, 0);
gimp_signal_private (SIGINT, gimp_sigfatal_handler, 0);
gimp_signal_private (SIGQUIT, gimp_sigfatal_handler, 0);
gimp_signal_private (SIGABRT, gimp_sigfatal_handler, 0);
gimp_signal_private (SIGBUS, gimp_sigfatal_handler, 0);
gimp_signal_private (SIGSEGV, gimp_sigfatal_handler, 0);
gimp_signal_private (SIGTERM, gimp_sigfatal_handler, 0);
gimp_signal_private (SIGFPE, gimp_sigfatal_handler, 0);
#ifndef __EMX__ /* OS/2 may not support SA_NOCLDSTOP -GRO */
/* Ignore SIGPIPE because plug_in.c handles broken pipes */
/* Disable child exit notification. This doesn't just block */
/* receipt of SIGCHLD, it in fact completely disables the */
/* generation of the signal by the OS. This behavior is */
/* mandated by POSIX.1. */
gimp_signal_private (SIGPIPE, SIG_IGN, 0);
gimp_signal_private (SIGCHLD, NULL, SA_NOCLDSTOP);
/* Collect dead children */
#endif
#endif
gimp_signal_private (SIGCHLD, gimp_sigchld_handler, SA_RESTART);
g_log_set_handler (NULL, G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL,
on_error, NULL);
#endif /* G_OS_WIN32 */
g_log_set_handler (NULL,
G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL,
gimp_error_handler,
NULL);
/* Keep the command line arguments--for use in gimp_init */
gimp_argc = argc - 1;
......@@ -403,10 +403,10 @@ init (void)
static void
on_error (const gchar *domain,
GLogLevelFlags flags,
const gchar *msg,
gpointer user_data)
gimp_error_handler (const gchar *domain,
GLogLevelFlags flags,
const gchar *msg,
gpointer user_data)
{
gimp_fatal_error ("%s", msg);
}
......@@ -416,56 +416,41 @@ on_error (const gchar *domain,
/* gimp core signal handler for fatal signals */
static void
on_signal (gint sig_num)
gimp_sigfatal_handler (gint sig_num)
{
static gboolean caught_fatal_sig = FALSE;
if (caught_fatal_sig)
kill (getpid (), sig_num);
caught_fatal_sig = TRUE;
switch (sig_num)
{
case SIGHUP:
gimp_terminate ("sighup caught");
break;
case SIGINT:
gimp_terminate ("sigint caught");
break;
case SIGQUIT:
gimp_terminate ("sigquit caught");
break;
case SIGABRT:
gimp_terminate ("sigabrt caught");
case SIGTERM:
gimp_terminate (g_strsignal (sig_num));
break;
case SIGBUS:
gimp_fatal_error ("sigbus caught");
break;
case SIGSEGV:
gimp_fatal_error ("sigsegv caught");
case SIGFPE:
default:
gimp_fatal_error (g_strsignal (sig_num));
break;
}
}
case SIGPIPE:
gimp_terminate ("sigpipe caught");
break;
/* gimp core signal handler for death-of-child signals */
case SIGTERM:
gimp_terminate ("sigterm caught");
break;
static void
gimp_sigchld_handler (gint sig_num)
{
gint pid;
gint status;
case SIGFPE:
gimp_fatal_error ("sigfpe caught");
break;
while (TRUE)
{
pid = waitpid (WAIT_ANY, &status, WNOHANG);
default:
gimp_fatal_error ("unknown signal");
break;
if (pid <= 0)
break;
}
}
......
......@@ -338,13 +338,11 @@ plug_in_init (void)
}
/* insert the proc defs */
tmp = gimprc_proc_defs;
while (tmp)
for (tmp = gimprc_proc_defs; tmp; tmp = g_slist_next (tmp))
{
proc_def = g_new (PlugInProcDef, 1);
*proc_def = *((PlugInProcDef*) tmp->data);
plug_in_proc_def_insert (proc_def, NULL);
tmp = tmp->next;
}
tmp = plug_in_defs;
......@@ -408,11 +406,9 @@ plug_in_init (void)
g_print ("\n");
/* free up stuff */
tmp = plug_in_defs;
while (tmp)
for (tmp = plug_in_defs; tmp; tmp = g_slist_next (tmp))
{
plug_in_def = tmp->data;
tmp = tmp->next;
plug_in_def_free (plug_in_def, FALSE);
}
......@@ -1033,10 +1029,11 @@ plug_in_open (PlugIn *plug_in)
if (!plug_in->synchronous)
{
plug_in->input_id = g_io_add_watch (plug_in->my_read,
G_IO_IN | G_IO_PRI,
plug_in_recv_message,
plug_in);
plug_in->input_id =
g_io_add_watch (plug_in->my_read,
G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
plug_in_recv_message,
plug_in);
open_plug_ins = g_slist_prepend (open_plug_ins, plug_in);
}
......@@ -1176,12 +1173,10 @@ plug_in_close (PlugIn *plug_in,
GSList *list;
PlugInProcDef *proc_def;
list = plug_in->temp_proc_defs;
while (list)
for (list = plug_in->temp_proc_defs; list; list = g_slist_next (list))
{
proc_def = (PlugInProcDef *) list->data;
plug_in_proc_def_remove (proc_def);
list = list->next;
}
g_slist_free (plug_in->temp_proc_defs);
......@@ -1189,9 +1184,9 @@ plug_in_close (PlugIn *plug_in,
}
/* Close any dialogs that this plugin might have opened */
brushes_check_dialogs();
patterns_check_dialogs();
gradients_check_dialogs();
brushes_check_dialogs ();
patterns_check_dialogs ();
gradients_check_dialogs ();
open_plug_ins = g_slist_remove (open_plug_ins, plug_in);
}
......@@ -1405,25 +1400,51 @@ plug_in_recv_message (GIOChannel *channel,
GIOCondition cond,
gpointer data)
{
WireMessage msg;
gboolean got_message = FALSE;
if ((PlugIn *) data != current_plug_in)
plug_in_push ((PlugIn *) data);
plug_in_push ((PlugIn*) data);
if (current_readchannel == NULL)
return TRUE;
memset (&msg, 0, sizeof (WireMessage));
if (!wire_read_msg (current_readchannel, &msg))
plug_in_close (current_plug_in, TRUE);
else
if (cond & (G_IO_IN | G_IO_PRI))
{
plug_in_handle_message (&msg);
wire_destroy (&msg);
WireMessage msg;
memset (&msg, 0, sizeof (WireMessage));
if (!wire_read_msg (current_readchannel, &msg))
{
plug_in_close (current_plug_in, TRUE);
}
else
{
plug_in_handle_message (&msg);
wire_destroy (&msg);
got_message = TRUE;
}
}
if (cond & (G_IO_ERR | G_IO_HUP))
{
if (current_plug_in->open)
{
plug_in_close (current_plug_in, TRUE);