From 44189f8129edff56668cad6846579adc0e64f8f3 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 11 Jul 2012 15:06:04 +0100 Subject: Use systemd for suspend and hibernate When running under systemd, call into systemd for suspend and hibernate instead of pm-utils. To capture resume events, install a small script that gets executed by systemd after resume and sends a dbus signal back to upower. To make this work, the upower backends gain a new signal, ::resuming, that they can optionally emit to signal that a resume happened. Backends opt in to this by returning TRUE from up_backend_emits_resuming(). In this case, upower doesn't assume the sleep command to block until resume, but instead waits for the ::resuming signal from the backend. The only backend that uses this mechanism is the linux backend when built with systemd support. Signed-off-by: Richard Hughes --- configure.ac | 57 ++++++++++++++++++++++++++++++++++------ src/Makefile.am | 12 +++++++-- src/dummy/up-backend.c | 6 +++++ src/freebsd/up-backend.c | 6 +++++ src/linux/Makefile.am | 3 ++- src/linux/up-backend.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ src/notify-upower.sh | 6 +++++ src/openbsd/up-backend.c | 6 +++++ src/up-backend.h | 2 ++ src/up-daemon.c | 61 ++++++++++++++++++++++++++++--------------- 10 files changed, 194 insertions(+), 32 deletions(-) create mode 100755 src/notify-upower.sh diff --git a/configure.ac b/configure.ac index 311c6f2..8d8710c 100644 --- a/configure.ac +++ b/configure.ac @@ -176,6 +176,55 @@ fi PKG_CHECK_MODULES(GIO, [gio-2.0 >= 2.16.1]) +dnl ==================================================================== +dnl Check for systemd +dnl ==================================================================== +AC_ARG_ENABLE([systemd], + AS_HELP_STRING([--enable-systemd], [Use systemd]), + [enable_systemd=$enableval], + [enable_systemd=auto]) + +PKG_CHECK_MODULES(SYSTEMD, + [libsystemd-daemon], + [have_systemd=yes], [have_systemd=no]) + +AC_MSG_CHECKING([whether to use systemd]) + +if test x$enable_systemd = xauto ; then + if test x$have_systemd = xno ; then + enable_systemd=no + else + enable_systemd=yes + fi +fi +AC_MSG_RESULT($enable_systemd) + +if test x$enable_systemd = xyes; then + if test x$have_systemd = xno; then + AC_MSG_ERROR([Systemd support explicitly required, but systemd not found]) + fi + AC_DEFINE(HAVE_SYSTEMD, 1, [Define if systemd is used for session tracking]) +fi + +AC_SUBST(SYSTEMD_CFLAGS) +AC_SUBST(SYSTEMD_LIBS) + +AM_CONDITIONAL(HAVE_SYSTEMD, [test "$with_systemd" = "yes"], [Using systemd]) + +AC_ARG_WITH([systemdutildir], + AS_HELP_STRING([--with-systemdutildir=DIR], [Directory for systemd utilities]), + [], + [with_systemdutildir=$($PKG_CONFIG --variable=systemdutildir systemd)]) +AC_SUBST([systemdutildir], [$with_systemdutildir]) +AM_CONDITIONAL(HAVE_SYSTEMDUTILDIR, [test -n "$with_systemdutildir"]) + +AC_ARG_WITH([systemdsystemunitdir], + AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]), + [], + [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)]) +AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) +AM_CONDITIONAL(HAVE_SYSTEMDSYSTEMUNITDIR, [test -n "$with_systemdsystemunitdir"]) + dnl --------------------------------------------------------------------------- dnl - Compile time default choice of backend dnl --------------------------------------------------------------------------- @@ -210,14 +259,6 @@ fi AM_CONDITIONAL(HAVE_IDEVICE, [test x$have_idevice = xyes]) -# systemd -AC_ARG_WITH([systemdsystemunitdir], - AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]), - [], - [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)]) -AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) -AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir"]) - # export to Makefile.am AM_CONDITIONAL(BACKEND_TYPE_DUMMY, [test x$with_backend = xdummy]) AM_CONDITIONAL(BACKEND_TYPE_LINUX, [test x$with_backend = xlinux]) diff --git a/src/Makefile.am b/src/Makefile.am index 0166861..0bf1165 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -122,7 +122,13 @@ upowerd_LDADD += \ linux/libupshared.la \ $(USB_LIBS) \ $(GUDEV_LIBS) \ - $(IDEVICE_LIBS) + $(IDEVICE_LIBS) \ + $(SYSTEMD_LIBS) + +if HAVE_SYSTEMDUTILDIR +systemsleepdir = $(systemdutildir)/system-sleep +systemsleep_SCRIPTS = notify-upower.sh +endif if UP_BUILD_TESTS DBUS_LAUNCH=$(shell which dbus-launch) @@ -196,7 +202,7 @@ dbusconf_DATA = $(dbusconf_in_files:.conf.in=.conf) $(dbusconf_DATA): $(dbusconf_in_files) Makefile cp $< $@ -if HAVE_SYSTEMD +if HAVE_SYSTEMDSYSTEMUNITDIR systemdservicedir = $(systemdsystemunitdir) systemdservice_in_files = upower.service.in systemdservice_DATA = $(systemdservice_in_files:.service.in=.service) @@ -223,6 +229,8 @@ EXTRA_DIST = \ org.freedesktop.UPower.KbdBacklight.xml \ org.freedesktop.UPower.Wakeups.xml \ up-marshal.list \ + $(systemsleep_SCRIPTS) \ + $(systemdservice_in_files) \ $(dbusservice_in_files) \ $(dbusconf_in_files) diff --git a/src/dummy/up-backend.c b/src/dummy/up-backend.c index 834e37d..b860eff 100644 --- a/src/dummy/up-backend.c +++ b/src/dummy/up-backend.c @@ -297,3 +297,9 @@ up_backend_get_powersave_command (UpBackend *backend, gboolean powersave) { return "/bin/true"; } + +gboolean +up_backend_emits_resuming (UpBackend *backend) +{ + return FALSE; +} diff --git a/src/freebsd/up-backend.c b/src/freebsd/up-backend.c index e1dd22a..40e8b2b 100644 --- a/src/freebsd/up-backend.c +++ b/src/freebsd/up-backend.c @@ -326,6 +326,12 @@ up_backend_get_hibernate_command (UpBackend *backend) return UP_BACKEND_HIBERNATE_COMMAND; } +gboolean +up_backend_emits_resuming (UpBackend *backend) +{ + return FALSE; +} + /** * up_backend_kernel_can_suspend: **/ diff --git a/src/linux/Makefile.am b/src/linux/Makefile.am index 520b4cf..2081a66 100644 --- a/src/linux/Makefile.am +++ b/src/linux/Makefile.am @@ -12,7 +12,8 @@ INCLUDES = \ $(GUDEV_CFLAGS) \ $(POLKIT_CFLAGS) \ $(GLIB_CFLAGS) \ - $(IDEVICE_CFLAGS) + $(IDEVICE_CFLAGS) \ + $(SYSTEMD_CFLAGS) if BACKEND_TYPE_LINUX noinst_LTLIBRARIES = libupshared.la diff --git a/src/linux/up-backend.c b/src/linux/up-backend.c index be01763..ddd4472 100644 --- a/src/linux/up-backend.c +++ b/src/linux/up-backend.c @@ -45,6 +45,17 @@ #include "up-device-idevice.h" #endif /* HAVE_IDEVICE */ +#include +#include + +#ifdef HAVE_SYSTEMD +#include + +#define SD_HIBERNATE_COMMAND "gdbus call --system --dest org.freedesktop.login1 --object-path /org/freedesktop/login1 --method org.freedesktop.login1.Manager.Hibernate 'true'" +#define SD_SUSPEND_COMMAND "gdbus call --system --dest org.freedesktop.login1 --object-path /org/freedesktop/login1 --method org.freedesktop.login1.Manager.Suspend 'true'" + +#endif + static void up_backend_class_init (UpBackendClass *klass); static void up_backend_init (UpBackend *backend); static void up_backend_finalize (GObject *object); @@ -59,11 +70,13 @@ struct UpBackendPrivate UpDeviceList *managed_devices; UpDock *dock; UpConfig *config; + DBusConnection *connection; }; enum { SIGNAL_DEVICE_ADDED, SIGNAL_DEVICE_REMOVED, + SIGNAL_RESUMING, SIGNAL_LAST }; @@ -564,6 +577,11 @@ out: const gchar * up_backend_get_suspend_command (UpBackend *backend) { +#ifdef HAVE_SYSTEMD + if (sd_booted ()) + return SD_SUSPEND_COMMAND; + else +#endif return UP_BACKEND_SUSPEND_COMMAND; } @@ -573,9 +591,24 @@ up_backend_get_suspend_command (UpBackend *backend) const gchar * up_backend_get_hibernate_command (UpBackend *backend) { +#ifdef HAVE_SYSTEMD + if (sd_booted ()) + return SD_HIBERNATE_COMMAND; + else +#endif return UP_BACKEND_HIBERNATE_COMMAND; } +gboolean +up_backend_emits_resuming (UpBackend *backend) +{ +#ifdef HAVE_SYSTEMD + return TRUE; +#else + return FALSE; +#endif +} + /** * up_backend_get_powersave_command: **/ @@ -609,10 +642,32 @@ up_backend_class_init (UpBackendClass *klass) G_STRUCT_OFFSET (UpBackendClass, device_removed), NULL, NULL, up_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); + signals [SIGNAL_RESUMING] = + g_signal_new ("resuming", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (UpBackendClass, resuming), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); g_type_class_add_private (klass, sizeof (UpBackendPrivate)); } +static DBusHandlerResult +message_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + UpBackend *backend = user_data; + + if (dbus_message_is_signal (message, "org.freedesktop.UPower", "Resuming")) { + g_debug ("received Resuming signal"); + g_signal_emit (backend, signals[SIGNAL_RESUMING], 0); + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + /** * up_backend_init: **/ @@ -624,6 +679,15 @@ up_backend_init (UpBackend *backend) backend->priv->daemon = NULL; backend->priv->device_list = NULL; backend->priv->managed_devices = up_device_list_new (); + +#ifdef HAVE_SYSTEMD + if (sd_booted ()) { + DBusGConnection *bus; + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL); + backend->priv->connection = dbus_g_connection_get_connection (bus); + dbus_connection_add_filter (backend->priv->connection, message_filter, backend, NULL); + } +#endif } /** @@ -648,6 +712,9 @@ up_backend_finalize (GObject *object) g_object_unref (backend->priv->managed_devices); + if (backend->priv->connection) + dbus_connection_remove_filter (backend->priv->connection, message_filter, backend); + G_OBJECT_CLASS (up_backend_parent_class)->finalize (object); } diff --git a/src/notify-upower.sh b/src/notify-upower.sh new file mode 100755 index 0000000..d88ae5e --- /dev/null +++ b/src/notify-upower.sh @@ -0,0 +1,6 @@ +#!/bin/bash +[ "$1" = "post" ] && exec /usr/bin/dbus-send \ + --system --type=signal \ + --dest=org.freedesktop.UPower \ + /org/freedesktop/UPower \ + org.freedesktop.UPower.Resuming diff --git a/src/openbsd/up-backend.c b/src/openbsd/up-backend.c index 9d724ba..b25fb44 100644 --- a/src/openbsd/up-backend.c +++ b/src/openbsd/up-backend.c @@ -205,6 +205,12 @@ up_backend_get_hibernate_command (UpBackend *backend) return NULL; } +gboolean +up_backend_emits_resuming (UpBackend *backend) +{ + return FALSE; +} + /** * up_backend_kernel_can_suspend: **/ diff --git a/src/up-backend.h b/src/up-backend.h index 154e2c6..08dac8b 100644 --- a/src/up-backend.h +++ b/src/up-backend.h @@ -59,6 +59,7 @@ typedef struct void (* device_removed) (UpBackend *backend, GObject *native, UpDevice *device); + void (* resuming) (UpBackend *backend); } UpBackendClass; GType up_backend_get_type (void); @@ -75,6 +76,7 @@ const gchar *up_backend_get_suspend_command (UpBackend *backend); const gchar *up_backend_get_hibernate_command (UpBackend *backend); const gchar *up_backend_get_powersave_command (UpBackend *backend, gboolean powersave); +gboolean up_backend_emits_resuming (UpBackend *backend); G_END_DECLS diff --git a/src/up-daemon.c b/src/up-daemon.c index 6165fab..be416ab 100644 --- a/src/up-daemon.c +++ b/src/up-daemon.c @@ -380,8 +380,40 @@ typedef struct { UpDaemon *daemon; DBusGMethodInvocation *context; gchar *command; + gulong handler; } UpDaemonDeferredSleep; +static void +emit_resuming (UpDaemonDeferredSleep *sleep) +{ + UpDaemon *daemon = sleep->daemon; + UpDaemonPrivate *priv = daemon->priv; + + /* emit signal for session components */ + g_debug ("emitting resuming"); + g_signal_emit (daemon, signals[SIGNAL_RESUMING], 0); + g_signal_emit (daemon, signals[SIGNAL_NOTIFY_RESUME], 0, + priv->sleep_kind); + + /* reset the about-to-sleep logic */ + g_timer_reset (priv->about_to_sleep_timer); + g_timer_stop (priv->about_to_sleep_timer); + + /* actually return from the DBus call now */ + dbus_g_method_return (sleep->context, NULL); + + /* clear timer */ + priv->about_to_sleep_id = 0; + priv->sent_sleeping_signal = FALSE; + + /* delete temp object */ + if (sleep->handler) + g_signal_handler_disconnect (priv->backend, sleep->handler); + g_object_unref (sleep->daemon); + g_free (sleep->command); + g_free (sleep); +} + /** * up_daemon_deferred_sleep_cb: **/ @@ -396,7 +428,13 @@ up_daemon_deferred_sleep_cb (UpDaemonDeferredSleep *sleep) UpDaemon *daemon = sleep->daemon; UpDaemonPrivate *priv = daemon->priv; + if (up_backend_emits_resuming (priv->backend)) { + sleep->handler = g_signal_connect_swapped (priv->backend, "resuming", + G_CALLBACK (emit_resuming), sleep); + } + /* run the command */ + g_debug ("Running %s", sleep->command); ret = g_spawn_command_line_sync (sleep->command, &stdout, &stderr, NULL, &error_local); if (!ret) { error = g_error_new (UP_DAEMON_ERROR, @@ -408,32 +446,13 @@ up_daemon_deferred_sleep_cb (UpDaemonDeferredSleep *sleep) goto out; } - /* emit signal for session components */ - g_debug ("emitting resuming"); - g_signal_emit (daemon, signals[SIGNAL_RESUMING], 0); - g_signal_emit (daemon, signals[SIGNAL_NOTIFY_RESUME], 0, - priv->sleep_kind); - - /* reset the about-to-sleep logic */ - g_timer_reset (priv->about_to_sleep_timer); - g_timer_stop (priv->about_to_sleep_timer); - - /* actually return from the DBus call now */ - dbus_g_method_return (sleep->context, NULL); + if (!up_backend_emits_resuming (priv->backend)) + emit_resuming (sleep); out: - /* clear timer */ - priv->about_to_sleep_id = 0; - priv->sent_sleeping_signal = FALSE; - g_free (stdout); g_free (stderr); - /* delete temp object */ - g_object_unref (sleep->daemon); - g_free (sleep->command); - g_free (sleep); - return FALSE; } -- cgit v1.2.3