summaryrefslogtreecommitdiffstats
path: root/src/sleep
diff options
context:
space:
mode:
authorSonali Srivastava <srivastava.sonali1@gmail.com>2022-07-27 08:23:21 +0200
committerLuca Boccassi <luca.boccassi@gmail.com>2022-08-09 18:13:35 +0200
commit746cf8980b204d7aa60d567a6223e0a5409f44f6 (patch)
treee610fdeb11bc64b9dda0d49dbbe937e854ee160b /src/sleep
parentNEWS: add entries for v252 (diff)
downloadsystemd-746cf8980b204d7aa60d567a6223e0a5409f44f6.tar.xz
systemd-746cf8980b204d7aa60d567a6223e0a5409f44f6.zip
sleep: support multiple battery instead of only BAT0
Diffstat (limited to 'src/sleep')
-rw-r--r--src/sleep/sleep.c64
1 files changed, 25 insertions, 39 deletions
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
index ff6c71d61b..14191cfc61 100644
--- a/src/sleep/sleep.c
+++ b/src/sleep/sleep.c
@@ -263,6 +263,7 @@ static int execute(
}
static int execute_s2h(const SleepConfig *sleep_config) {
+ _cleanup_hashmap_free_ Hashmap *last_capacity = NULL, *current_capacity = NULL;
int r;
assert(sleep_config);
@@ -270,42 +271,29 @@ static int execute_s2h(const SleepConfig *sleep_config) {
while (battery_is_low() == 0) {
_cleanup_close_ int tfd = -1;
struct itimerspec ts = {};
- usec_t suspend_interval = sleep_config->hibernate_delay_sec, before_timestamp = 0, after_timestamp = 0;
+ usec_t suspend_interval = sleep_config->hibernate_delay_sec, before_timestamp = 0, after_timestamp = 0, total_suspend_interval;
bool woken_by_timer;
- int last_capacity = 0, current_capacity = 0, previous_discharge_rate, estimated_discharge_rate = 0;
tfd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK|TFD_CLOEXEC);
if (tfd < 0)
return log_error_errno(errno, "Error creating timerfd: %m");
/* Store current battery capacity and current time before suspension */
- r = read_battery_capacity_percentage();
- if (r >= 0) {
- last_capacity = r;
- log_debug("Current battery charge percentage: %d%%", last_capacity);
+ r = fetch_batteries_capacity_by_name(&last_capacity);
+ if (r >= 0)
before_timestamp = now(CLOCK_BOOTTIME);
- } else if (r == -ENOENT)
+ else if (r == -ENOENT)
/* In case of no battery, system suspend interval will be set to HibernateDelaySec=. */
log_debug_errno(r, "Suspend Interval value set to %s: %m", FORMAT_TIMESPAN(suspend_interval, USEC_PER_SEC));
else
return log_error_errno(r, "Error fetching battery capacity percentage: %m");
- r = get_battery_discharge_rate();
+ r = get_total_suspend_interval(last_capacity, &total_suspend_interval);
if (r < 0)
- log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to get discharge rate, ignoring: %m");
- else if (last_capacity * 2 <= r) {
- /* System should hibernate in case discharge rate is higher than double of battery current capacity
- * why double : Because while calculating suspend interval, we have taken a buffer of 30 minute and
- * discharge_rate is calculated on per 60 minute basis which is double. Also suspend_interval > 0 */
- log_debug("Current battery percentage capacity too low to suspend, so invoking hibernation");
- break;
- } else {
- previous_discharge_rate = r;
- assert(previous_discharge_rate != 0);
- suspend_interval = usec_sub_unsigned(last_capacity * USEC_PER_HOUR / previous_discharge_rate, 30 * USEC_PER_MINUTE);
- /* The previous discharge rate is stored in per hour basis so converted to minutes.
- * Subtracted 30 minutes from the result to keep a buffer of 30 minutes before battery gets critical */
- }
+ log_debug_errno(r, "Failed to estimate suspend interval using previous discharge rate, ignoring: %m");
+ else
+ suspend_interval = total_suspend_interval;
+
log_debug("Set timerfd wake alarm for %s", FORMAT_TIMESPAN(suspend_interval, USEC_PER_SEC));
/* Wake alarm for system with or without battery to hibernate or estimate discharge rate whichever is applicable */
timespec_store(&ts.it_value, suspend_interval);
@@ -323,28 +311,26 @@ static int execute_s2h(const SleepConfig *sleep_config) {
/* Store fd_wait status */
woken_by_timer = FLAGS_SET(r, POLLIN);
- r = read_battery_capacity_percentage();
- if (r >= 0) {
- current_capacity = r;
- log_debug("Current battery charge percentage after wakeup: %d%%", current_capacity);
- } else if (r == -ENOENT) {
- /* In case of no battery, system will be hibernated after 1st cycle of suspend */
+ r = fetch_batteries_capacity_by_name(&current_capacity);
+ if (r < 0) {
+ /* In case of no battery or error while getting charge level, no need to measure
+ * discharge rate. Instead system should wakeup if it is manual wakeup or
+ * hibernate if this is a timer wakeup. */
log_debug_errno(r, "Battery capacity percentage unavailable, cannot estimate discharge rate: %m");
+ if (!woken_by_timer)
+ return 0;
break;
- } else
- return log_error_errno(r, "Error fetching battery capacity percentage: %m");
+ }
- if (current_capacity >= last_capacity)
- log_debug("Battery was not discharged during suspension");
- else {
- after_timestamp = now(CLOCK_BOOTTIME);
- log_debug("Attempting to estimate battery discharge rate after wakeup from %s sleep", FORMAT_TIMESPAN(after_timestamp - before_timestamp, USEC_PER_HOUR));
+ after_timestamp = now(CLOCK_BOOTTIME);
+ log_debug("Attempting to estimate battery discharge rate after wakeup from %s sleep", FORMAT_TIMESPAN(after_timestamp - before_timestamp, USEC_PER_HOUR));
- estimated_discharge_rate = (last_capacity - current_capacity) * USEC_PER_HOUR / (after_timestamp - before_timestamp);
- r = put_battery_discharge_rate(estimated_discharge_rate);
+ if (after_timestamp != before_timestamp) {
+ r = estimate_battery_discharge_rate_per_hour(last_capacity, current_capacity, before_timestamp, after_timestamp);
if (r < 0)
- log_warning_errno(r, "Failed to update battery discharge rate, ignoring: %m");
- }
+ log_warning_errno(r, "Failed to estimate and update battery discharge rate, ignoring: %m");
+ } else
+ log_debug("System woke up too early to estimate discharge rate");
if (!woken_by_timer)
/* Return as manual wakeup done. This also will return in case battery was charged during suspension */