[gdm] server: Process SIGUSR1 more carefully
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gdm] server: Process SIGUSR1 more carefully
- Date: Fri, 14 Feb 2014 20:49:55 +0000 (UTC)
commit 956d7d1c7a0cfbf2beacdb9e88e645e15ad32047
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Fri Feb 14 14:32:50 2014 -0500
server: Process SIGUSR1 more carefully
If the slave is removed as a separate process, it means that we need
to be more careful with our handling of SIGUSR1. If multiple X servers
are launched at once, we need to use siginfo_t to get the PID of the
thing that sent the user signal, and make sure we signal the correct
GdmServer.
glib doesn't have native siginfo support, so do it ourselves by using
a worker thread that spins around waiting for sigwaitinfo.
https://bugzilla.gnome.org/show_bug.cgi?id=724382
daemon/gdm-server.c | 86 ++++++++++++++++++++++++++++++++++++++++++--------
daemon/main.c | 15 +++++++++
2 files changed, 87 insertions(+), 14 deletions(-)
---
diff --git a/daemon/gdm-server.c b/daemon/gdm-server.c
index 1606b3a..fe012a2 100644
--- a/daemon/gdm-server.c
+++ b/daemon/gdm-server.c
@@ -94,7 +94,6 @@ struct GdmServerPrivate
char *auth_file;
guint child_watch_id;
- guint sigusr1_id;
gboolean is_initial;
};
@@ -180,16 +179,77 @@ gdm_server_get_display_device (GdmServer *server)
return g_strdup (server->priv->display_device);
}
+static void
+gdm_server_ready (GdmServer *server)
+{
+ g_debug ("GdmServer: Got USR1 from X server - emitting READY");
+ g_signal_emit (server, signals[READY], 0);
+}
+
+static GSList *active_servers;
+static gboolean sigusr1_thread_running;
+static GCond sigusr1_thread_cond;
+static GMutex sigusr1_thread_mutex;
+
static gboolean
-on_sigusr1 (gpointer user_data)
+got_sigusr1 (gpointer user_data)
+{
+ GPid pid = GPOINTER_TO_UINT (user_data);
+ GSList *l;
+
+ g_debug ("GdmServer: got SIGUSR1 from PID %d", pid);
+ for (l = active_servers; l; l = l->next) {
+ GdmServer *server = l->data;
+
+ if (server->priv->pid == pid)
+ gdm_server_ready (server);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static gpointer
+sigusr1_thread_main (gpointer user_data)
{
- GdmServer *server = user_data;
+ sigset_t sigusr1_mask;
- g_debug ("GdmServer: Got USR1 from X server - emitting READY");
+ /* Handle only SIGUSR1 */
+ sigemptyset (&sigusr1_mask);
+ sigaddset (&sigusr1_mask, SIGUSR1);
+ sigprocmask (SIG_SETMASK, &sigusr1_mask, NULL);
- g_signal_emit (server, signals[READY], 0);
- return FALSE;
+ g_mutex_lock (&sigusr1_thread_mutex);
+ sigusr1_thread_running = TRUE;
+ g_cond_signal (&sigusr1_thread_cond);
+ g_mutex_unlock (&sigusr1_thread_mutex);
+
+ /* Spin waiting for a SIGUSR1 */
+ while (TRUE) {
+ siginfo_t info;
+
+ if (sigwaitinfo (&sigusr1_mask, &info) == -1)
+ continue;
+
+ g_idle_add (got_sigusr1, GUINT_TO_POINTER (info.si_pid));
+ }
+
+ return NULL;
+}
+
+static void
+gdm_server_launch_sigusr1_thread_if_needed (void)
+{
+ static GThread *sigusr1_thread;
+
+ if (sigusr1_thread == NULL) {
+ sigusr1_thread = g_thread_new ("gdm SIGUSR1 catcher", sigusr1_thread_main, NULL);
+
+ g_mutex_lock (&sigusr1_thread_mutex);
+ while (!sigusr1_thread_running)
+ g_cond_wait (&sigusr1_thread_cond, &sigusr1_thread_mutex);
+ g_mutex_unlock (&sigusr1_thread_mutex);
+ }
}
/* We keep a connection (parent_dsp) open with the parent X server
@@ -676,6 +736,8 @@ server_child_watch (GPid pid,
g_signal_emit (server, signals [DIED], 0, num);
}
+ active_servers = g_slist_remove (active_servers, server);
+
g_spawn_close_pid (server->priv->pid);
server->priv->pid = -1;
@@ -719,6 +781,10 @@ gdm_server_spawn (GdmServer *server,
g_debug ("GdmServer: Starting X server process: %s", freeme);
g_free (freeme);
+ active_servers = g_slist_append (active_servers, server);
+
+ gdm_server_launch_sigusr1_thread_if_needed ();
+
if (!g_spawn_async_with_pipes (NULL,
argv,
(char **)env->pdata,
@@ -1063,16 +1129,11 @@ gdm_server_class_init (GdmServerClass *klass)
static void
gdm_server_init (GdmServer *server)
{
-
server->priv = GDM_SERVER_GET_PRIVATE (server);
server->priv->pid = -1;
server->priv->log_dir = g_strdup (LOGDIR);
-
- server->priv->sigusr1_id = g_unix_signal_add (SIGUSR1,
- on_sigusr1,
- server);
}
static void
@@ -1087,9 +1148,6 @@ gdm_server_finalize (GObject *object)
g_return_if_fail (server->priv != NULL);
- if (server->priv->sigusr1_id > 0)
- g_source_remove (server->priv->sigusr1_id);
-
gdm_server_stop (server);
g_free (server->priv->command);
diff --git a/daemon/main.c b/daemon/main.c
index d008aac..cdb41fa 100644
--- a/daemon/main.c
+++ b/daemon/main.c
@@ -295,6 +295,19 @@ is_debug_set (void)
return debug;
}
+/* SIGUSR1 is used by the X server to tell us that we're ready, so
+ * block it. We'll unblock it in the worker thread in gdm-server.c
+ */
+static void
+block_sigusr1 (void)
+{
+ sigset_t mask;
+
+ sigemptyset (&mask);
+ sigaddset (&mask, SIGUSR1);
+ sigprocmask (SIG_BLOCK, &mask, NULL);
+}
+
int
main (int argc,
char **argv)
@@ -315,6 +328,8 @@ main (int argc,
{ NULL }
};
+ block_sigusr1 ();
+
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
textdomain (GETTEXT_PACKAGE);
setlocale (LC_ALL, "");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]