Fix handling of SIGCHLD

The commit that removed metacity-dialog added a global SIGCHLD handler
that caused problems by (a) calling waitpid(-1) and thus breaking
g_child_watch for everyone else, and (b) doing too much from a signal
handler and sometimes causing deadlocks (bug 596200).

This removes the global handler and has each zenity user create its
own child watch to watch for exit. (It also fixes the window class of
the zenity dialogs, so that meta_window_present_delete_dialog() will
work again.)
This commit is contained in:
Dan Winship 2009-11-19 17:38:06 -05:00
parent 5e2c66e241
commit 988d2ffab6
5 changed files with 24 additions and 136 deletions

View File

@ -55,27 +55,16 @@ delete_ping_reply_func (MetaDisplay *display,
/* we do nothing */ /* we do nothing */
} }
static gboolean
delete_window_callback (gpointer w_p)
{
meta_window_kill ((MetaWindow*) w_p);
return FALSE; /* don't do it again */
}
static void static void
sigchld_handler (MetaNexus *nexus, guint arg1, gpointer arg2, gpointer user_data) dialog_exited (GPid pid, int status, gpointer user_data)
{ {
MetaWindow *ours = (MetaWindow*) user_data; MetaWindow *ours = (MetaWindow*) user_data;
if (GPOINTER_TO_INT (arg2) == ours->dialog_pid) ours->dialog_pid = -1;
{
if (arg1 == 1 /* pressed "force quit" */)
g_idle_add_full (G_PRIORITY_DEFAULT,
delete_window_callback, user_data, NULL);
ours->dialog_pid = -1; /* forget it anyway */ /* exit status of 1 means the user pressed "Force Quit" */
} if (WIFEXITED (status) && WEXITSTATUS (status) == 1)
meta_window_kill (ours);
} }
static void static void
@ -119,11 +108,7 @@ delete_ping_timeout_func (MetaDisplay *display,
g_free (window_content); g_free (window_content);
window->dialog_pid = dialog_pid; window->dialog_pid = dialog_pid;
g_child_watch_add (dialog_pid, dialog_exited, window);
g_signal_connect (sigchld_nexus, "sigchld",
G_CALLBACK (sigchld_handler),
window);
} }
void void

View File

@ -444,29 +444,6 @@ sigterm_handler (int signum)
exit (meta_exit_code); exit (meta_exit_code);
} }
static guint sigchld_signal_id = 0;
static void
sigchld_handler (int signum, siginfo_t *info, void *context)
{
int stat;
if (info->si_code == CLD_EXITED)
{
g_signal_emit (sigchld_nexus, sigchld_signal_id, 0,
info->si_status,
GINT_TO_POINTER (info->si_pid));
}
g_signal_handlers_disconnect_matched (sigchld_nexus,
G_SIGNAL_MATCH_DATA,
sigchld_signal_id,
0, NULL, NULL,
GINT_TO_POINTER (info->si_pid));
waitpid (info->si_pid, &stat, WNOHANG);
}
/** /**
* This is where the story begins. It parses commandline options and * This is where the story begins. It parses commandline options and
* environment variables, sets up the screen, hands control off to * environment variables, sets up the screen, hands control off to
@ -517,24 +494,6 @@ main (int argc, char **argv)
g_printerr ("Failed to register SIGTERM handler: %s\n", g_printerr ("Failed to register SIGTERM handler: %s\n",
g_strerror (errno)); g_strerror (errno));
sigchld_nexus = g_object_new (META_TYPE_NEXUS, NULL);
sigchld_signal_id =
g_signal_new ("sigchld", META_TYPE_NEXUS,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__UINT_POINTER,
G_TYPE_NONE,
2,
G_TYPE_UINT, G_TYPE_POINTER);
act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
act.sa_handler = SIG_DFL;
act.sa_sigaction = &sigchld_handler;
if (sigaction (SIGCHLD, &act, NULL) < 0)
g_printerr ("Failed to register SIGCHLD handler: %s\n",
g_strerror (errno));
if (g_getenv ("MUTTER_VERBOSE")) if (g_getenv ("MUTTER_VERBOSE"))
meta_set_verbose (TRUE); meta_set_verbose (TRUE);
if (g_getenv ("MUTTER_DEBUG")) if (g_getenv ("MUTTER_DEBUG"))

View File

@ -29,6 +29,7 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <time.h> #include <time.h>
#include <sys/wait.h>
#ifndef HAVE_SM #ifndef HAVE_SM
void void
@ -1749,11 +1750,11 @@ finish_interact (gboolean shutdown)
} }
static void static void
sigchld_handler (MetaNexus *nexus, guint arg1, gpointer arg2, gpointer user_data) dialog_closed (GPid pid, int status, gpointer user_data)
{ {
gboolean shutdown = GPOINTER_TO_INT (user_data); gboolean shutdown = GPOINTER_TO_INT (user_data);
if (arg1 == 0) /* pressed "OK" */ if (WIFEXITED (status) && WEXITSTATUS (status) == 0) /* pressed "OK" */
{ {
finish_interact (shutdown); finish_interact (shutdown);
} }
@ -1767,6 +1768,7 @@ warn_about_lame_clients_and_finish_interact (gboolean shutdown)
GSList *lame_details = NULL; GSList *lame_details = NULL;
GSList *tmp; GSList *tmp;
GSList *columns = NULL; GSList *columns = NULL;
GPid pid;
windows = meta_display_list_windows (meta_get_display (), META_LIST_DEFAULT); windows = meta_display_list_windows (meta_get_display (), META_LIST_DEFAULT);
tmp = windows; tmp = windows;
@ -1814,7 +1816,7 @@ warn_about_lame_clients_and_finish_interact (gboolean shutdown)
} }
g_slist_free (lame); g_slist_free (lame);
meta_show_dialog("--list", pid = meta_show_dialog("--list",
_("These windows do not support &quot;save current setup&quot; " _("These windows do not support &quot;save current setup&quot; "
"and will have to be restarted manually next time " "and will have to be restarted manually next time "
"you log in."), "you log in."),
@ -1827,10 +1829,7 @@ warn_about_lame_clients_and_finish_interact (gboolean shutdown)
g_slist_free (lame_details); g_slist_free (lame_details);
g_signal_connect (sigchld_nexus, "sigchld", g_child_watch_add (pid, dialog_closed, GINT_TO_POINTER (shutdown));
G_CALLBACK (sigchld_handler),
GINT_TO_POINTER (shutdown));
} }
#endif /* HAVE_SM */ #endif /* HAVE_SM */

View File

@ -40,8 +40,6 @@
#include <X11/Xlib.h> /* must explicitly be included for Solaris; #326746 */ #include <X11/Xlib.h> /* must explicitly be included for Solaris; #326746 */
#include <X11/Xutil.h> /* Just for the definition of the various gravities */ #include <X11/Xutil.h> /* Just for the definition of the various gravities */
MetaNexus *sigchld_nexus;
#ifdef HAVE_BACKTRACE #ifdef HAVE_BACKTRACE
#include <execinfo.h> #include <execinfo.h>
void void
@ -560,7 +558,7 @@ meta_show_dialog (const char *type,
int i=0; int i=0;
GPid child_pid; GPid child_pid;
const char **argvl = g_malloc(sizeof (char*) * const char **argvl = g_malloc(sizeof (char*) *
(15 + (17 +
g_slist_length (columns)*2 + g_slist_length (columns)*2 +
g_slist_length (entries))); g_slist_length (entries)));
@ -568,6 +566,8 @@ meta_show_dialog (const char *type,
argvl[i++] = type; argvl[i++] = type;
argvl[i++] = "--screen"; argvl[i++] = "--screen";
argvl[i++] = screen_number_text; argvl[i++] = screen_number_text;
argvl[i++] = "--class";
argvl[i++] = "mutter-dialog";
argvl[i++] = "--title"; argvl[i++] = "--title";
/* Translators: This is the title used on dialog boxes */ /* Translators: This is the title used on dialog boxes */
argvl[i++] = _("Mutter"); argvl[i++] = _("Mutter");
@ -641,31 +641,6 @@ meta_show_dialog (const char *type,
return child_pid; return child_pid;
} }
GType
meta_nexus_get_type (void)
{
static GType nexus_type = 0;
if (!nexus_type)
{
static const GTypeInfo nexus_info =
{
sizeof (MetaNexusClass),
NULL, NULL, NULL, NULL, NULL,
sizeof (MetaNexus),
0,
NULL, NULL
};
nexus_type = g_type_register_static (G_TYPE_OBJECT,
"MetaNexus",
&nexus_info,
0);
}
return nexus_type;
}
/*************************************************************************** /***************************************************************************
* Later functions: like idles but integrated with the Clutter repaint loop * Later functions: like idles but integrated with the Clutter repaint loop
***************************************************************************/ ***************************************************************************/

View File

@ -131,36 +131,6 @@ GPid meta_show_dialog (const char *type,
#endif /* !WITH_VERBOSE_MODE */ #endif /* !WITH_VERBOSE_MODE */
#include <glib-object.h>
#define META_TYPE_NEXUS (meta_nexus_get_type ())
#define META_NEXUS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_NEXUS, MetaNexus))
#define META_NEXUS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_NEXUS, MetaNexusClass))
#define META_IS_NEXUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_NEXUS))
#define META_IS_NEXUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_NEXUS))
#define META_NEXUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_NEXUS, MetaNexusClass))
typedef struct _MetaNexus
{
GObject parent_instance;
} MetaNexus;
typedef struct _MetaNexusClass
{
GObjectClass parent_class;
} MetaNexusClass;
GType meta_nexus_get_type (void) G_GNUC_CONST;
MetaNexus *meta_nexus_new ();
/**
* An object which exists purely to attach signals to; this is to receive
* signals when a child process exits. The signal is "sigchld" with no detail.
*
* \bug Eventually we should have a specialised type for objects like these.
*/
extern MetaNexus *sigchld_nexus;
/** /**
* MetaLaterType: * MetaLaterType:
* @META_LATER_RESIZE: call in a resize processing phase that is done * @META_LATER_RESIZE: call in a resize processing phase that is done