]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemd-sleep: replace rtc wakealarm with CLOCK_BOOTTIME_ALARM s2h
authorZach Smith <z@zxmth.us>
Thu, 16 May 2019 16:12:41 +0000 (11:12 -0500)
committerLennart Poettering <lennart@poettering.net>
Tue, 28 May 2019 15:02:36 +0000 (17:02 +0200)
refactor to use timerfd in place of rtc wakealarm

confirm CLOCK_BOOTTIME_ALARM support in can_s2h

Remove CLOCK_BOOTTIME_ALARM task from TODO

remove unnecessary check on clock_supported return

TODO
src/shared/sleep-config.c
src/sleep/sleep.c

diff --git a/TODO b/TODO
index e8f59d0932fb325f4b3f996103ebcab43dd64d10..4507c16878b687b5c4fb08809cc33476273653c5 100644 (file)
--- a/TODO
+++ b/TODO
@@ -34,7 +34,6 @@ Features:
   cgroup.
 
 * clean up sleep.c:
-  - Use CLOCK_BOOTTIME_ALARM for waking up s2h instead of RTC ioctls
   - Parse sleep.conf only once, and parse its whole contents so that we don't
     have to parse it again and again in s2h
   - Make sure resume= and resume_offset= on the kernel cmdline always take
index 0e114a7b49a94869b72844444b216e6e3ca8b626..cba7afdd11d0da3cd636074e98f80d2d9da13fbc 100644 (file)
@@ -30,6 +30,7 @@
 #include "sleep-config.h"
 #include "string-util.h"
 #include "strv.h"
+#include "time-util.h"
 
 int parse_sleep_config(const char *verb, bool *ret_allow, char ***ret_modes, char ***ret_states, usec_t *ret_delay) {
         int allow_suspend = -1, allow_hibernate = -1,
@@ -383,10 +384,9 @@ static bool can_s2h(void) {
         const char *p;
         int r;
 
-        r = access("/sys/class/rtc/rtc0/wakealarm", W_OK);
-        if (r < 0) {
+        if (!clock_supported(CLOCK_BOOTTIME_ALARM)) {
                 log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
-                         "/sys/class/rtc/rtc0/wakealarm is not writable %m");
+                         "CLOCK_BOOTTIME_ALARM is not supported");
                 return false;
         }
 
index ed570deaee09ba0f097eb8e42ce939151fecbf69..2510ccc72b8b6c3b113ed591ea0c34ea8fefd9af 100644 (file)
@@ -8,9 +8,11 @@
 #include <fcntl.h>
 #include <getopt.h>
 #include <linux/fiemap.h>
+#include <poll.h>
 #include <stdio.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/timerfd.h>
 #include <unistd.h>
 
 #include "sd-messages.h"
@@ -28,6 +30,7 @@
 #include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "time-util.h"
 #include "util.h"
 
 static char* arg_verb = NULL;
@@ -196,39 +199,13 @@ static int execute(char **modes, char **states) {
         return r;
 }
 
-static int rtc_read_time(uint64_t *ret_sec) {
-        _cleanup_free_ char *t = NULL;
-        int r;
-
-        r = read_one_line_file("/sys/class/rtc/rtc0/since_epoch", &t);
-        if (r < 0)
-                return log_error_errno(r, "Failed to read RTC time: %m");
-
-        r = safe_atou64(t, ret_sec);
-        if (r < 0)
-                return log_error_errno(r, "Failed to parse RTC time '%s': %m", t);
-
-        return 0;
-}
-
-static int rtc_write_wake_alarm(uint64_t sec) {
-        char buf[DECIMAL_STR_MAX(uint64_t)];
-        int r;
-
-        xsprintf(buf, "%" PRIu64, sec);
-
-        r = write_string_file("/sys/class/rtc/rtc0/wakealarm", buf, WRITE_STRING_FILE_DISABLE_BUFFER);
-        if (r < 0)
-                return log_error_errno(r, "Failed to write '%s' to /sys/class/rtc/rtc0/wakealarm: %m", buf);
-
-        return 0;
-}
-
 static int execute_s2h(usec_t hibernate_delay_sec) {
-
         _cleanup_strv_free_ char **hibernate_modes = NULL, **hibernate_states = NULL,
                                  **suspend_modes = NULL, **suspend_states = NULL;
-        usec_t original_time, wake_time, cmp_time;
+        _cleanup_close_ int tfd = -1;
+        char buf[FORMAT_TIMESPAN_MAX];
+        struct itimerspec ts = {};
+        struct pollfd fds;
         int r;
 
         r = parse_sleep_config("suspend", NULL, &suspend_modes, &suspend_states, NULL);
@@ -239,36 +216,39 @@ static int execute_s2h(usec_t hibernate_delay_sec) {
         if (r < 0)
                 return r;
 
-        r = rtc_read_time(&original_time);
-        if (r < 0)
-                return r;
+        tfd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK|TFD_CLOEXEC);
+        if (tfd < 0)
+                return log_error_errno(errno, "Error creating timerfd: %m");
 
-        wake_time = original_time + DIV_ROUND_UP(hibernate_delay_sec, USEC_PER_SEC);
-        r = rtc_write_wake_alarm(wake_time);
-        if (r < 0)
-                return r;
+        log_debug("Set timerfd wake alarm for %s",
+                  format_timespan(buf, sizeof(buf), hibernate_delay_sec, USEC_PER_SEC));
 
-        log_debug("Set RTC wake alarm for %" PRIu64, wake_time);
+        timespec_store(&ts.it_value, hibernate_delay_sec);
 
-        r = execute(suspend_modes, suspend_states);
+        r = timerfd_settime(tfd, 0, &ts, NULL);
         if (r < 0)
-                return r;
+                return log_error_errno(errno, "Error setting hibernate timer: %m");
 
-        /* Reset RTC right-away */
-        r = rtc_write_wake_alarm(0);
+        r = execute(suspend_modes, suspend_states);
         if (r < 0)
                 return r;
 
-        r = rtc_read_time(&cmp_time);
+        fds = (struct pollfd) {
+                .fd = tfd,
+                .events = POLLIN,
+        };
+        r = poll(&fds, 1, 0);
         if (r < 0)
-                return r;
+                return log_error_errno(errno, "Error polling timerfd: %m");
 
-        log_debug("Woke up at %"PRIu64, cmp_time);
+        tfd = safe_close(tfd);
 
-        if (cmp_time < wake_time) /* We woke up before the alarm time, we are done. */
+        if (!FLAGS_SET(fds.revents, POLLIN)) /* We woke up before the alarm time, we are done. */
                 return 0;
 
         /* If woken up after alarm time, hibernate */
+        log_debug("Attempting to hibernate after waking from %s timer",
+                  format_timespan(buf, sizeof(buf), hibernate_delay_sec, USEC_PER_SEC));
         r = execute(hibernate_modes, hibernate_states);
         if (r < 0) {
                 log_notice("Couldn't hibernate, will try to suspend again.");