[gnome-shell/benzea/systemd-3.36-units] windowManager: Wait for X11 services using systemd
- From: Benjamin Berg <bberg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/benzea/systemd-3.36-units] windowManager: Wait for X11 services using systemd
- Date: Wed, 15 Jul 2020 21:56:43 +0000 (UTC)
commit d0ce609d876ee86987783df996e6060c106ab171
Author: Benjamin Berg <bberg redhat com>
Date: Fri Dec 13 19:07:16 2019 +0100
windowManager: Wait for X11 services using systemd
To do this, we now wait for the start/stop job to complete. We also have
two targets in gnome-session to ensure that everything is working as
expected.
In order to start the services, we simply request the
gnome-session-x11-services-ready.target unit, and wait for it to become
available. To stop, we use the gnome-session-x11-services.target unit
which should stop all services in a way that is entirely race free.
This requires both gnome-session and gnome-settings-daemon changes to
work (which are in the corresponding merge requests).
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/895
js/ui/windowManager.js | 58 +++++++-------
src/shell-util.c | 201 +++++++++++++++++++++++++++++++++++++++++--------
src/shell-util.h | 21 ++++--
3 files changed, 216 insertions(+), 64 deletions(-)
---
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
index 2ff1ffdcbb..945e680308 100644
--- a/js/ui/windowManager.js
+++ b/js/ui/windowManager.js
@@ -901,43 +901,45 @@ var WindowManager = class {
global.display.connect('init-xserver', (display, task) => {
IBusManager.getIBusManager().restartDaemon(['--xim']);
- try {
- if (!Shell.util_start_systemd_unit('gsd-xsettings.target', 'fail'))
- log('Not starting gsd-xsettings; waiting for gnome-session to do so');
-
- /* Leave this watchdog timeout so don't block indefinitely here */
- let timeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 5, () => {
- Gio.DBus.session.unwatch_name(watchId);
- log('Warning: Failed to start gsd-xsettings');
- task.return_boolean(true);
- timeoutId = 0;
- return GLib.SOURCE_REMOVE;
- });
+ log('Starting X11 services from init-xserver callback');
- /* When gsd-xsettings daemon is started, we are good to resume */
- let watchId = Gio.DBus.session.watch_name(
- 'org.gnome.SettingsDaemon.XSettings',
- Gio.BusNameWatcherFlags.NONE,
- () => {
- Gio.DBus.session.unwatch_name(watchId);
- if (timeoutId > 0) {
- task.return_boolean(true);
- GLib.source_remove(timeoutId);
- }
- },
- null);
- } catch (e) {
- log('Error starting gsd-xsettings: %s'.format(e.message));
+ /* Start a watchdog timeout so we don't block indefinitely here */
+ let cancellable = new Gio.Cancellable();
+ let timeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 5, () => {
+ log('Warning: Failed to start X11 services');
+ cancellable.cancel();
task.return_boolean(true);
- }
+ timeoutId = 0;
+ return GLib.SOURCE_REMOVE;
+ });
+
+ Shell.util_start_systemd_unit('gnome-session-x11-services-ready.target',
+ 'fail',
+ cancellable,
+ (obj, res) => {
+ try {
+ res = Shell.util_start_systemd_unit_finish(res);
+ log('Starting X11 services job result was:
%s'.format(res));
+ } catch (e) {
+ if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
+ return;
+
+ log('Error starting X11 services: %s'.format(e.message));
+ }
+
+ task.return_boolean(true);
+ GLib.source_remove(timeoutId);
+ });
return true;
});
global.display.connect('x11-display-closing', () => {
+ log('Stopping X11 services from x11-display-closing callback');
+
if (!Meta.is_wayland_compositor())
return;
try {
- Shell.util_stop_systemd_unit('gsd-xsettings.target', 'fail');
+ Shell.util_stop_systemd_unit('gnome-session-x11-services.target', 'fail', null, () => {});
} catch (e) {
log('Error stopping gsd-xsettings: %s'.format(e.message));
}
diff --git a/src/shell-util.c b/src/shell-util.c
index 5fe2dfcaf5..a14b5827d3 100644
--- a/src/shell-util.c
+++ b/src/shell-util.c
@@ -625,6 +625,53 @@ shell_util_get_uid (void)
return getuid ();
}
+typedef struct {
+ GDBusConnection *connection;
+ gchar *command;
+
+ GCancellable *cancellable;
+ gulong cancel_id;
+
+ guint job_watch;
+ gchar *job;
+} SystemdCall;
+
+static void
+shell_util_systemd_call_data_free (SystemdCall *data)
+{
+ if (data->job_watch)
+ {
+ g_dbus_connection_signal_unsubscribe (data->connection, data->job_watch);
+ data->job_watch = 0;
+ }
+
+ if (data->cancellable)
+ {
+ g_cancellable_disconnect (data->cancellable, data->cancel_id);
+ g_clear_object (&data->cancellable);
+ data->cancel_id = 0;
+ }
+
+ g_clear_object (&data->connection);
+ g_clear_pointer (&data->job, g_free);
+ g_clear_pointer (&data->command, g_free);
+ g_free (data);
+}
+
+static void
+shell_util_systemd_call_cancelled_cb (GCancellable *cancellable,
+ GTask *task)
+{
+ SystemdCall *data = g_task_get_task_data (task);
+
+ /* We are still in the DBus call; it will return the error. */
+ if (data->job == NULL)
+ return;
+
+ /* Return the cancellation error now. */
+ g_assert (g_task_return_error_if_cancelled (task));
+}
+
static void
on_systemd_call_cb (GObject *source,
GAsyncResult *res,
@@ -632,46 +679,123 @@ on_systemd_call_cb (GObject *source,
{
g_autoptr (GVariant) reply = NULL;
g_autoptr (GError) error = NULL;
- const gchar *command = user_data;
+ GTask *task = G_TASK (user_data);
+ SystemdCall *data;
reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source),
res, &error);
- if (error)
- g_warning ("Could not issue '%s' systemd call", command);
+
+ data = g_task_get_task_data (task);
+
+ if (error) {
+ g_warning ("Could not issue '%s' systemd call", data->command);
+ g_task_return_error (task, g_steal_pointer (&error));
+ g_object_unref (task);
+
+ return;
+ }
+
+ g_assert (data->job == NULL);
+ g_variant_get (reply, "(o)", &data->job);
+
+ /* And we wait for the JobRemoved notification. */
}
-static gboolean
-shell_util_systemd_call (const char *command,
- const char *unit,
- const char *mode,
- GError **error)
+static void
+on_systemd_job_removed_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ SystemdCall *data;
+ guint32 id;
+ const char *path, *unit, *result;
+
+ data = g_task_get_task_data (task);
+
+ /* No job information yet, ignore. */
+ if (data->job == NULL)
+ return;
+
+ g_variant_get (parameters, "(u&o&s&s)", &id, &path, &unit, &result);
+
+ /* Is it the job we are waiting for? */
+ if (g_strcmp0 (path, data->job) != 0)
+ return;
+
+ /* Task has completed; return the result of the job */
+ g_task_return_pointer (task, g_strdup (result), g_free);
+ g_object_unref (task);
+}
+
+static void
+shell_util_systemd_call (const char *command,
+ const char *unit,
+ const char *mode,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
#ifdef HAVE_SYSTEMD
g_autoptr (GDBusConnection) connection = NULL;
+ g_autoptr (GTask) task = NULL;
+ GError *error = NULL;
+ SystemdCall *data;
g_autofree char *self_unit = NULL;
int res;
+ task = g_task_new (NULL, cancellable, callback, user_data);
+
+ connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+
+ if (connection == NULL) {
+ g_task_return_error (task, error);
+ return;
+ }
+
res = sd_pid_get_user_unit (getpid (), &self_unit);
if (res == -ENODATA)
{
g_debug ("Not systemd-managed, not doing '%s' on '%s'", mode, unit);
- return FALSE;
+ g_task_return_pointer (task, g_strdup ("not-systemd-managed"), g_free);
}
else if (res < 0)
{
- g_set_error (error,
+ g_set_error (&error,
G_IO_ERROR,
g_io_error_from_errno (-res),
"Error trying to start systemd unit '%s': %s",
unit, g_strerror (-res));
- return FALSE;
+ g_task_return_error (task, error);
}
- connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
-
- if (connection == NULL)
- return FALSE;
+ data = g_new0 (SystemdCall, 1);
+ data->command = g_strdup (command);
+ data->connection = g_object_ref (connection);
+ data->job_watch = g_dbus_connection_signal_subscribe (connection,
+ "org.freedesktop.systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "JobRemoved",
+ "/org/freedesktop/systemd1",
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ on_systemd_job_removed_cb,
+ g_object_ref (task),
+ g_object_unref);
+ g_task_set_task_data (task,
+ data,
+ (GDestroyNotify) shell_util_systemd_call_data_free);
+
+ if (cancellable)
+ data->cancel_id = g_cancellable_connect (cancellable,
+ G_CALLBACK (shell_util_systemd_call_cancelled_cb),
+ task,
+ NULL);
g_dbus_connection_call (connection,
"org.freedesktop.systemd1",
@@ -680,31 +804,48 @@ shell_util_systemd_call (const char *command,
command,
g_variant_new ("(ss)",
unit, mode),
- NULL,
+ G_VARIANT_TYPE ("(o)"),
G_DBUS_CALL_FLAGS_NONE,
- -1, NULL,
+ -1, cancellable,
on_systemd_call_cb,
- (gpointer) command);
- return TRUE;
+ g_steal_pointer (&task));
#endif /* HAVE_SYSTEMD */
+}
- return FALSE;
+void
+shell_util_start_systemd_unit (const char *unit,
+ const char *mode,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ shell_util_systemd_call ("StartUnit", unit, mode,
+ cancellable, callback, user_data);
}
-gboolean
-shell_util_start_systemd_unit (const char *unit,
- const char *mode,
- GError **error)
+gchar*
+shell_util_start_systemd_unit_finish (GAsyncResult *res,
+ GError **error)
{
- return shell_util_systemd_call ("StartUnit", unit, mode, error);
+ return g_task_propagate_pointer (G_TASK (res), error);
}
-gboolean
-shell_util_stop_systemd_unit (const char *unit,
- const char *mode,
- GError **error)
+void
+shell_util_stop_systemd_unit (const char *unit,
+ const char *mode,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ shell_util_systemd_call ("StopUnit", unit, mode,
+ cancellable, callback, user_data);
+}
+
+gchar*
+shell_util_stop_systemd_unit_finish (GAsyncResult *res,
+ GError **error)
{
- return shell_util_systemd_call ("StopUnit", unit, mode, error);
+ return g_task_propagate_pointer (G_TASK (res), error);
}
void
diff --git a/src/shell-util.h b/src/shell-util.h
index 00127ca957..04f92830b7 100644
--- a/src/shell-util.h
+++ b/src/shell-util.h
@@ -62,12 +62,21 @@ cairo_surface_t * shell_util_composite_capture_images (ClutterCapture *captures
void shell_util_check_cloexec_fds (void);
-gboolean shell_util_start_systemd_unit (const char *unit,
- const char *mode,
- GError **error);
-gboolean shell_util_stop_systemd_unit (const char *unit,
- const char *mode,
- GError **error);
+void shell_util_start_systemd_unit (const char *unit,
+ const char *mode,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gchar* shell_util_start_systemd_unit_finish (GAsyncResult *res,
+ GError **error);
+
+void shell_util_stop_systemd_unit (const char *unit,
+ const char *mode,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gchar* shell_util_stop_systemd_unit_finish (GAsyncResult *res,
+ GError **error);
void shell_util_sd_notify (void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]