diff options
author | Mario Limonciello <superm1@gmail.com> | 2018-03-08 21:17:33 +0800 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2018-03-08 14:17:33 +0100 |
commit | c58493c00af97146d3b6c24da9c0371978124703 (patch) | |
tree | eef8dce2e68194b33df3faec0631bee8543a175b /src/shared | |
parent | fc17f194ded93b51899aa0bbd4e66870d975fe5a (diff) | |
download | systemd-c58493c00af97146d3b6c24da9c0371978124703.tar.gz |
Introduce suspend-to-hibernate (#8274)
Suspend to Hibernate is a new sleep method that invokes suspend
for a predefined period of time before automatically waking up
and hibernating the system.
It's similar to HybridSleep however there isn't a performance
impact on every suspend cycle.
It's intended to use with systems that may have a higher power
drain in their supported suspend states to prevent battery and
data loss over an extended suspend cycle.
Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/sleep-config.c | 54 | ||||
-rw-r--r-- | src/shared/sleep-config.h | 4 |
2 files changed, 50 insertions, 8 deletions
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index ecac98e0ab..feb2c5281d 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -3,6 +3,7 @@ This file is part of systemd. Copyright 2013 Zbigniew Jędrzejewski-Szmek + Copyright 2018 Dell Inc. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -41,13 +42,14 @@ #define USE(x, y) do { (x) = (y); (y) = NULL; } while (0) -int parse_sleep_config(const char *verb, char ***_modes, char ***_states) { +int parse_sleep_config(const char *verb, char ***_modes, char ***_states, usec_t *_delay) { _cleanup_strv_free_ char **suspend_mode = NULL, **suspend_state = NULL, **hibernate_mode = NULL, **hibernate_state = NULL, **hybrid_mode = NULL, **hybrid_state = NULL; char **modes, **states; + usec_t delay; const ConfigTableItem items[] = { { "Sleep", "SuspendMode", config_parse_strv, 0, &suspend_mode }, @@ -56,6 +58,7 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) { { "Sleep", "HibernateState", config_parse_strv, 0, &hibernate_state }, { "Sleep", "HybridSleepMode", config_parse_strv, 0, &hybrid_mode }, { "Sleep", "HybridSleepState", config_parse_strv, 0, &hybrid_state }, + { "Sleep", "HibernateDelaySec", config_parse_sec, 0, &delay}, {} }; @@ -94,18 +97,26 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) { USE(states, hybrid_state); else states = strv_new("disk", NULL); - + } else if (streq(verb, "suspend-to-hibernate")) { + if (delay == 0) + delay = 180 * USEC_PER_MINUTE; } else assert_not_reached("what verb"); - if ((!modes && !streq(verb, "suspend")) || !states) { + if ((!modes && (streq(verb, "hibernate") || streq(verb, "hybrid-sleep"))) || + (!states && !streq(verb, "suspend-to-hibernate"))) { strv_free(modes); strv_free(states); return log_oom(); } - *_modes = modes; - *_states = states; + if (_modes) + *_modes = modes; + if (_states) + *_states = states; + if (_delay) + *_delay = delay; + return 0; } @@ -260,15 +271,44 @@ static bool enough_memory_for_hibernation(void) { return r; } +static bool can_s2h(void) { + int r; + + r = access("/sys/class/rtc/rtc0/wakealarm", W_OK); + if (r < 0) { + log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, + "/sys/class/rct/rct0/wakealarm is not writable %m"); + return false; + } + + r = can_sleep("suspend"); + if (r < 0) { + log_debug_errno(r, "Unable to suspend system."); + return false; + } + + r = can_sleep("hibernate"); + if (r < 0) { + log_debug_errno(r, "Unable to hibernate system."); + return false; + } + + return true; +} + int can_sleep(const char *verb) { _cleanup_strv_free_ char **modes = NULL, **states = NULL; int r; assert(streq(verb, "suspend") || streq(verb, "hibernate") || - streq(verb, "hybrid-sleep")); + streq(verb, "hybrid-sleep") || + streq(verb, "suspend-to-hibernate")); + + if (streq(verb, "suspend-to-hibernate")) + return can_s2h(); - r = parse_sleep_config(verb, &modes, &states); + r = parse_sleep_config(verb, &modes, &states, NULL); if (r < 0) return false; diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h index fc5a81d954..3dacda0d80 100644 --- a/src/shared/sleep-config.h +++ b/src/shared/sleep-config.h @@ -20,7 +20,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -int parse_sleep_config(const char *verb, char ***modes, char ***states); +#include "time-util.h" + +int parse_sleep_config(const char *verb, char ***modes, char ***states, usec_t *delay); int can_sleep(const char *verb); int can_sleep_disk(char **types); |