From 46fadc83c114540c0ec0adb191e0a8f7a7d897c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Rechi=20Vita?= <jprvita@endlessm.com>
Date: Fri, 10 Jul 2015 12:52:04 -0400
Subject: [PATCH 1/3] Make gdm-session-worker exit cleanly
Calling gdm_session_stop_conversation() in gdm_launch_environment_stop()
sends a SIGTERM to gdm-session-worker without waiting for it to die. The
next step is calling gdm_session_close() to close the session, which
stops all conversations of that session object, sending a 2nd SIGTERM to
gdm-session-worker, this time waiting on its PID.
On gdm-session-worker side, the first SIGTERM is caught by
on_shutdown_signal(), its custom SIGTERM handler, which quits the
mainloop and unrefs the worker object. Quiting the mainloop replaces the
custom SIGTERM handler with the system default one (exit immediately).
During the worker object class finalization gdm-session-worker may
receive the 2nd SIGTERM, which leads to its immediate termination,
without waiting for its children, which in turn leads to the main gdm
process exit.
Since systemd relies on the SIGCHLD from the main gdm process to tell
when the service has stopped, this behavior breaks any unit that has a
Conflicts=gdm.service entry and relies on the X server not being around
when it is started.
This commit removes the call to gdm_session_stop_conversation() in
gdm_launch_environment_stop() and leaves it to be stopped in
gdm_session_close().
[endlessm/eos-shell#4921]
https://bugzilla.gnome.org/show_bug.cgi?id=752388
---
daemon/gdm-launch-environment.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/daemon/gdm-launch-environment.c b/daemon/gdm-launch-environment.c
index 4aee187..af3bf87 100644
--- a/daemon/gdm-launch-environment.c
+++ b/daemon/gdm-launch-environment.c
@@ -402,61 +402,60 @@ gdm_launch_environment_start (GdmLaunchEnvironment *launch_environment)
gdm_session_start_conversation (launch_environment->priv->session, "gdm-launch-environment");
if (launch_environment->priv->dbus_session_bus_address) {
gdm_session_select_program (launch_environment->priv->session, launch_environment->priv->command);
} else {
/* wrap it in dbus-launch */
char *command = g_strdup_printf ("%s %s", DBUS_LAUNCH_COMMAND, launch_environment->priv->command);
gdm_session_select_program (launch_environment->priv->session, command);
g_free (command);
}
res = TRUE;
out:
if (local_error) {
g_critical ("GdmLaunchEnvironment: %s", local_error->message);
g_clear_error (&local_error);
}
return res;
}
gboolean
gdm_launch_environment_stop (GdmLaunchEnvironment *launch_environment)
{
if (launch_environment->priv->pid > 1) {
gdm_signal_pid (-launch_environment->priv->pid, SIGTERM);
}
if (launch_environment->priv->session != NULL) {
- gdm_session_stop_conversation (launch_environment->priv->session, "gdm-launch-environment");
gdm_session_close (launch_environment->priv->session);
g_clear_object (&launch_environment->priv->session);
}
g_signal_emit (G_OBJECT (launch_environment), signals [STOPPED], 0);
return TRUE;
}
GdmSession *
gdm_launch_environment_get_session (GdmLaunchEnvironment *launch_environment)
{
return launch_environment->priv->session;
}
char *
gdm_launch_environment_get_session_id (GdmLaunchEnvironment *launch_environment)
{
return g_strdup (launch_environment->priv->session_id);
}
static void
_gdm_launch_environment_set_verification_mode (GdmLaunchEnvironment *launch_environment,
GdmSessionVerificationMode verification_mode)
{
launch_environment->priv->verification_mode = verification_mode;
}
static void
--
2.3.7
From 92564b47a85f9a308f7bfc34b8017f2767bf4677 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 4 Mar 2015 11:12:24 -0500
Subject: [PATCH 2/3] manager: clean up manager in dispose not finalize
Seems more appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=745975
---
daemon/gdm-manager.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index f060135..e0af40c 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -75,61 +75,61 @@ struct GdmManagerPrivate
GHashTable *transient_sessions;
GHashTable *open_reauthentication_requests;
gboolean xdmcp_enabled;
GCancellable *cancellable;
gboolean started;
gboolean wait_for_go;
gboolean show_local_greeter;
GDBusProxy *bus_proxy;
GDBusConnection *connection;
GDBusObjectManagerServer *object_manager;
};
enum {
PROP_0,
PROP_XDMCP_ENABLED,
PROP_SHOW_LOCAL_GREETER
};
enum {
DISPLAY_ADDED,
DISPLAY_REMOVED,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0, };
static void gdm_manager_class_init (GdmManagerClass *klass);
static void gdm_manager_init (GdmManager *manager);
-static void gdm_manager_finalize (GObject *object);
+static void gdm_manager_dispose (GObject *object);
static void create_seed_session_for_display (GdmManager *manager,
GdmDisplay *display,
uid_t allowed_user);
static void touch_ran_once_marker_file (GdmManager *manager);
static gpointer manager_object = NULL;
static void manager_interface_init (GdmDBusManagerIface *interface);
G_DEFINE_TYPE_WITH_CODE (GdmManager,
gdm_manager,
GDM_DBUS_TYPE_MANAGER_SKELETON,
G_IMPLEMENT_INTERFACE (GDM_DBUS_TYPE_MANAGER,
manager_interface_init));
#ifdef WITH_SYSTEMD
static char *
get_session_id_for_pid_systemd (pid_t pid,
GError **error)
{
char *session, *gsession;
int ret;
session = NULL;
ret = sd_pid_get_session (pid, &session);
if (ret < 0) {
g_set_error (error,
GDM_DISPLAY_ERROR,
GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
"Error getting session id from systemd: %s",
@@ -2186,61 +2186,61 @@ gdm_manager_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GdmManager *manager;
manager = GDM_MANAGER (G_OBJECT_CLASS (gdm_manager_parent_class)->constructor (type,
n_construct_properties,
construct_properties));
gdm_dbus_manager_set_version (GDM_DBUS_MANAGER (manager), PACKAGE_VERSION);
manager->priv->local_factory = gdm_local_display_factory_new (manager->priv->display_store);
#ifdef HAVE_LIBXDMCP
if (manager->priv->xdmcp_enabled) {
manager->priv->xdmcp_factory = gdm_xdmcp_display_factory_new (manager->priv->display_store);
}
#endif
return G_OBJECT (manager);
}
static void
gdm_manager_class_init (GdmManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gdm_manager_get_property;
object_class->set_property = gdm_manager_set_property;
object_class->constructor = gdm_manager_constructor;
- object_class->finalize = gdm_manager_finalize;
+ object_class->dispose = gdm_manager_dispose;
signals [DISPLAY_ADDED] =
g_signal_new ("display-added",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GdmManagerClass, display_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
1, G_TYPE_STRING);
signals [DISPLAY_REMOVED] =
g_signal_new ("display-removed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GdmManagerClass, display_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
1, G_TYPE_STRING);
g_object_class_install_property (object_class,
PROP_XDMCP_ENABLED,
g_param_spec_boolean ("xdmcp-enabled",
NULL,
NULL,
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
@@ -2271,100 +2271,105 @@ gdm_manager_init (GdmManager *manager)
"display-added",
G_CALLBACK (on_display_added),
manager);
g_signal_connect (G_OBJECT (manager->priv->display_store),
"display-removed",
G_CALLBACK (on_display_removed),
manager);
}
static void
unexport_display (const char *id,
GdmDisplay *display,
GdmManager *manager)
{
if (!g_dbus_connection_is_closed (manager->priv->connection))
g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);
}
static void
finish_display (const char *id,
GdmDisplay *display,
GdmManager *manager)
{
if (gdm_display_get_status (display) == GDM_DISPLAY_MANAGED)
gdm_display_unmanage (display);
gdm_display_finish (display);
}
static void
-gdm_manager_finalize (GObject *object)
+gdm_manager_dispose (GObject *object)
{
GdmManager *manager;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_MANAGER (object));
manager = GDM_MANAGER (object);
g_return_if_fail (manager->priv != NULL);
#ifdef HAVE_LIBXDMCP
g_clear_object (&manager->priv->xdmcp_factory);
#endif
g_clear_object (&manager->priv->local_factory);
- g_hash_table_unref (manager->priv->open_reauthentication_requests);
- g_hash_table_unref (manager->priv->transient_sessions);
+ g_clear_pointer (&manager->priv->open_reauthentication_requests,
+ (GDestroyNotify)
+ g_hash_table_unref);
+ g_clear_pointer (&manager->priv->transient_sessions,
+ (GDestroyNotify)
+ g_hash_table_unref);
+
g_list_free_full (manager->priv->user_sessions, (GDestroyNotify) g_object_unref);
manager->priv->user_sessions = NULL;
g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store),
G_CALLBACK (on_display_added),
manager);
g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store),
G_CALLBACK (on_display_removed),
manager);
if (!g_dbus_connection_is_closed (manager->priv->connection)) {
gdm_display_store_foreach (manager->priv->display_store,
(GdmDisplayStoreFunc)unexport_display,
manager);
g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (manager));
}
gdm_display_store_foreach (manager->priv->display_store,
(GdmDisplayStoreFunc) finish_display,
manager);
gdm_display_store_clear (manager->priv->display_store);
g_dbus_object_manager_server_set_connection (manager->priv->object_manager, NULL);
g_clear_object (&manager->priv->connection);
g_clear_object (&manager->priv->object_manager);
- g_object_unref (manager->priv->display_store);
+ g_clear_object (&manager->priv->display_store);
- G_OBJECT_CLASS (gdm_manager_parent_class)->finalize (object);
+ G_OBJECT_CLASS (gdm_manager_parent_class)->dispose (object);
}
GdmManager *
gdm_manager_new (void)
{
if (manager_object != NULL) {
g_object_ref (manager_object);
} else {
gboolean res;
manager_object = g_object_new (GDM_TYPE_MANAGER, NULL);
g_object_add_weak_pointer (manager_object,
(gpointer *) &manager_object);
res = register_manager (manager_object);
if (! res) {
g_object_unref (manager_object);
return NULL;
}
}
return GDM_MANAGER (manager_object);
}
--
2.3.7
From c6243ccc362cb51bb87043e18108d99117abd6c1 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 4 Mar 2015 11:17:05 -0500
Subject: [PATCH 3/3] manager: make sure to explicitly close user sessions in
dispose
We don't want ref count leaks to lead to unkilled sessions.
https://bugzilla.gnome.org/show_bug.cgi?id=745975
---
daemon/gdm-manager.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index e0af40c..12520ac 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -2293,60 +2293,63 @@ finish_display (const char *id,
GdmManager *manager)
{
if (gdm_display_get_status (display) == GDM_DISPLAY_MANAGED)
gdm_display_unmanage (display);
gdm_display_finish (display);
}
static void
gdm_manager_dispose (GObject *object)
{
GdmManager *manager;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_MANAGER (object));
manager = GDM_MANAGER (object);
g_return_if_fail (manager->priv != NULL);
#ifdef HAVE_LIBXDMCP
g_clear_object (&manager->priv->xdmcp_factory);
#endif
g_clear_object (&manager->priv->local_factory);
g_clear_pointer (&manager->priv->open_reauthentication_requests,
(GDestroyNotify)
g_hash_table_unref);
g_clear_pointer (&manager->priv->transient_sessions,
(GDestroyNotify)
g_hash_table_unref);
+ g_list_foreach (manager->priv->user_sessions,
+ (GFunc) gdm_session_close,
+ NULL);
g_list_free_full (manager->priv->user_sessions, (GDestroyNotify) g_object_unref);
manager->priv->user_sessions = NULL;
g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store),
G_CALLBACK (on_display_added),
manager);
g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store),
G_CALLBACK (on_display_removed),
manager);
if (!g_dbus_connection_is_closed (manager->priv->connection)) {
gdm_display_store_foreach (manager->priv->display_store,
(GdmDisplayStoreFunc)unexport_display,
manager);
g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (manager));
}
gdm_display_store_foreach (manager->priv->display_store,
(GdmDisplayStoreFunc) finish_display,
manager);
gdm_display_store_clear (manager->priv->display_store);
g_dbus_object_manager_server_set_connection (manager->priv->object_manager, NULL);
g_clear_object (&manager->priv->connection);
g_clear_object (&manager->priv->object_manager);
g_clear_object (&manager->priv->display_store);
--
2.3.7