util: Improve systemd start/stop API to permit waiting for job
In some cases it may be interesting to wait for the start/stop job to complete. Improve the API to be asynchronous and add the appropriate watches for systemd. Only return the task once the start or stop job has been removed again on the systemd side.
This commit is contained in:
parent
9115f6e796
commit
b92afe6a63
@ -1044,10 +1044,10 @@ var WindowManager = class {
|
||||
|
||||
global.display.connect('x11-display-opened', () => {
|
||||
IBusManager.getIBusManager().restartDaemon(['--xim']);
|
||||
Shell.util_start_systemd_unit('gnome-session-x11-services.target', 'fail');
|
||||
Shell.util_start_systemd_unit('gnome-session-x11-services.target', 'fail', null, () => {});
|
||||
});
|
||||
global.display.connect('x11-display-closing', () => {
|
||||
Shell.util_stop_systemd_unit('gnome-session-x11-services.target', 'fail');
|
||||
Shell.util_stop_systemd_unit('gnome-session-x11-services.target', 'fail', null, () => {});
|
||||
IBusManager.getIBusManager().restartDaemon();
|
||||
});
|
||||
|
||||
|
183
src/shell-util.c
183
src/shell-util.c
@ -573,6 +573,53 @@ shell_util_check_cloexec_fds (void)
|
||||
g_info ("Open fd CLOEXEC check complete");
|
||||
}
|
||||
|
||||
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,
|
||||
@ -580,26 +627,103 @@ 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, 0, "(o)", &data->job);
|
||||
|
||||
/* And we wait for the JobRemoved notification. */
|
||||
}
|
||||
|
||||
static gboolean
|
||||
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,
|
||||
GError **error)
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr (GDBusConnection) connection = NULL;
|
||||
g_autoptr (GTask) task = NULL;
|
||||
GError *error = NULL;
|
||||
SystemdCall *data;
|
||||
|
||||
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
|
||||
task = g_task_new (NULL, cancellable, callback, user_data);
|
||||
|
||||
if (connection == NULL)
|
||||
return FALSE;
|
||||
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
||||
|
||||
if (connection == NULL) {
|
||||
g_task_return_error (task, error);
|
||||
return;
|
||||
}
|
||||
|
||||
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",
|
||||
@ -608,28 +732,49 @@ 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));
|
||||
}
|
||||
|
||||
gboolean
|
||||
void
|
||||
shell_util_start_systemd_unit (const char *unit,
|
||||
const char *mode,
|
||||
GError **error)
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
return shell_util_systemd_call ("StartUnit", unit, mode, error);
|
||||
shell_util_systemd_call ("StartUnit", unit, mode,
|
||||
cancellable, callback, user_data);
|
||||
}
|
||||
|
||||
gboolean
|
||||
shell_util_stop_systemd_unit (const char *unit,
|
||||
const char *mode,
|
||||
gchar*
|
||||
shell_util_start_systemd_unit_finish (GObject *obj,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return shell_util_systemd_call ("StopUnit", unit, mode, error);
|
||||
return g_task_propagate_pointer (G_TASK (res), 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 (GObject *obj,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -57,11 +57,22 @@ 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,
|
||||
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 (GObject *obj,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
gboolean shell_util_stop_systemd_unit (const char *unit,
|
||||
|
||||
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 (GObject *obj,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
void shell_util_sd_notify (void);
|
||||
|
Loading…
Reference in New Issue
Block a user