summaryrefslogtreecommitdiff
path: root/daemon/gdm-server.c
diff options
context:
space:
mode:
authorJasper St. Pierre <jstpierre@mecheye.net>2014-02-14 14:32:50 -0500
committerJasper St. Pierre <jstpierre@mecheye.net>2014-02-14 15:49:30 -0500
commit956d7d1c7a0cfbf2beacdb9e88e645e15ad32047 (patch)
tree20599df6ad1a974be928ef455a320996d3c0b7a1 /daemon/gdm-server.c
parent98a32e4ff97bb52060c4fc053eed153d98a80bc9 (diff)
downloadgdm-956d7d1c7a0cfbf2beacdb9e88e645e15ad32047.tar.gz
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
Diffstat (limited to 'daemon/gdm-server.c')
-rw-r--r--daemon/gdm-server.c86
1 files changed, 72 insertions, 14 deletions
diff --git a/daemon/gdm-server.c b/daemon/gdm-server.c
index 1606b3af..fe012a26 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);