summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorMario Limonciello <superm1@gmail.com>2018-03-08 21:17:33 +0800
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2018-03-08 14:17:33 +0100
commitc58493c00af97146d3b6c24da9c0371978124703 (patch)
treeeef8dce2e68194b33df3faec0631bee8543a175b /src/shared
parentfc17f194ded93b51899aa0bbd4e66870d975fe5a (diff)
downloadsystemd-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.c54
-rw-r--r--src/shared/sleep-config.h4
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);