systemd-sleep: replace rtc wakealarm with CLOCK_BOOTTIME_ALARM s2h

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
This commit is contained in:
Zach Smith 2019-05-16 11:12:41 -05:00 committed by Lennart Poettering
parent 46fcf95dbe
commit 1bbbefe7a6
3 changed files with 30 additions and 51 deletions

1
TODO
View File

@ -34,7 +34,6 @@ Features:
cgroup. cgroup.
* clean up sleep.c: * 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 - Parse sleep.conf only once, and parse its whole contents so that we don't
have to parse it again and again in s2h have to parse it again and again in s2h
- Make sure resume= and resume_offset= on the kernel cmdline always take - Make sure resume= and resume_offset= on the kernel cmdline always take

View File

@ -30,6 +30,7 @@
#include "sleep-config.h" #include "sleep-config.h"
#include "string-util.h" #include "string-util.h"
#include "strv.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 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, int allow_suspend = -1, allow_hibernate = -1,
@ -383,10 +384,9 @@ static bool can_s2h(void) {
const char *p; const char *p;
int r; int r;
r = access("/sys/class/rtc/rtc0/wakealarm", W_OK); if (!clock_supported(CLOCK_BOOTTIME_ALARM)) {
if (r < 0) {
log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, 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; return false;
} }

View File

@ -8,9 +8,11 @@
#include <fcntl.h> #include <fcntl.h>
#include <getopt.h> #include <getopt.h>
#include <linux/fiemap.h> #include <linux/fiemap.h>
#include <poll.h>
#include <stdio.h> #include <stdio.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/timerfd.h>
#include <unistd.h> #include <unistd.h>
#include "sd-messages.h" #include "sd-messages.h"
@ -28,6 +30,7 @@
#include "stdio-util.h" #include "stdio-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "time-util.h"
#include "util.h" #include "util.h"
static char* arg_verb = NULL; static char* arg_verb = NULL;
@ -196,39 +199,13 @@ static int execute(char **modes, char **states) {
return r; 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) { static int execute_s2h(usec_t hibernate_delay_sec) {
_cleanup_strv_free_ char **hibernate_modes = NULL, **hibernate_states = NULL, _cleanup_strv_free_ char **hibernate_modes = NULL, **hibernate_states = NULL,
**suspend_modes = NULL, **suspend_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; int r;
r = parse_sleep_config("suspend", NULL, &suspend_modes, &suspend_states, NULL); 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) if (r < 0)
return r; return r;
r = rtc_read_time(&original_time); tfd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK|TFD_CLOEXEC);
if (r < 0) if (tfd < 0)
return r; return log_error_errno(errno, "Error creating timerfd: %m");
wake_time = original_time + DIV_ROUND_UP(hibernate_delay_sec, USEC_PER_SEC); log_debug("Set timerfd wake alarm for %s",
r = rtc_write_wake_alarm(wake_time); format_timespan(buf, sizeof(buf), hibernate_delay_sec, USEC_PER_SEC));
if (r < 0)
return r;
log_debug("Set RTC wake alarm for %" PRIu64, wake_time); timespec_store(&ts.it_value, hibernate_delay_sec);
r = timerfd_settime(tfd, 0, &ts, NULL);
if (r < 0)
return log_error_errno(errno, "Error setting hibernate timer: %m");
r = execute(suspend_modes, suspend_states); r = execute(suspend_modes, suspend_states);
if (r < 0) if (r < 0)
return r; return r;
/* Reset RTC right-away */ fds = (struct pollfd) {
r = rtc_write_wake_alarm(0); .fd = tfd,
.events = POLLIN,
};
r = poll(&fds, 1, 0);
if (r < 0) if (r < 0)
return r; return log_error_errno(errno, "Error polling timerfd: %m");
r = rtc_read_time(&cmp_time); tfd = safe_close(tfd);
if (r < 0)
return r;
log_debug("Woke up at %"PRIu64, cmp_time); if (!FLAGS_SET(fds.revents, POLLIN)) /* We woke up before the alarm time, we are done. */
if (cmp_time < wake_time) /* We woke up before the alarm time, we are done. */
return 0; return 0;
/* If woken up after alarm time, hibernate */ /* 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); r = execute(hibernate_modes, hibernate_states);
if (r < 0) { if (r < 0) {
log_notice("Couldn't hibernate, will try to suspend again."); log_notice("Couldn't hibernate, will try to suspend again.");