summaryrefslogtreecommitdiff
path: root/src/login/logind.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2012-12-23 22:32:48 +0100
committerLennart Poettering <lennart@poettering.net>2012-12-24 00:29:40 +0100
commit23406ce58aa7142e8df3c5c9e5ac34a01e90e3e0 (patch)
tree5175b16d46a7dfe59afaf2c8dd85f1b4081f7979 /src/login/logind.c
parent0ad1271f564b9c956685938167f7ea8c301e835e (diff)
logind: add support for automatic suspend/hibernate/shutdown on idle
Diffstat (limited to 'src/login/logind.c')
-rw-r--r--src/login/logind.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/login/logind.c b/src/login/logind.c
index 9cce481340..6438631b59 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -28,6 +28,7 @@
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <linux/vt.h>
+#include <sys/timerfd.h>
#include <systemd/sd-daemon.h>
@@ -61,6 +62,11 @@ Manager *manager_new(void) {
m->handle_lid_switch = HANDLE_SUSPEND;
m->lid_switch_ignore_inhibited = true;
+ m->idle_action_fd = -1;
+ m->idle_action_usec = 30 * USEC_PER_MINUTE;
+ m->idle_action = HANDLE_IGNORE;
+ m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
+
m->devices = hashmap_new(string_hash_func, string_compare_func);
m->seats = hashmap_new(string_hash_func, string_compare_func);
m->sessions = hashmap_new(string_hash_func, string_compare_func);
@@ -173,6 +179,9 @@ void manager_free(Manager *m) {
if (m->reserve_vt_fd >= 0)
close_nointr_nofail(m->reserve_vt_fd);
+ if (m->idle_action_fd >= 0)
+ close_nointr_nofail(m->idle_action_fd);
+
strv_free(m->controllers);
strv_free(m->reset_controllers);
strv_free(m->kill_only_users);
@@ -1441,6 +1450,79 @@ int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
return idle_hint;
}
+int manager_dispatch_idle_action(Manager *m) {
+ struct dual_timestamp since;
+ struct itimerspec its;
+ int r;
+ usec_t n;
+
+ assert(m);
+
+ if (m->idle_action == HANDLE_IGNORE ||
+ m->idle_action_usec <= 0) {
+ r = 0;
+ goto finish;
+ }
+
+ zero(its);
+ n = now(CLOCK_MONOTONIC);
+
+ r = manager_get_idle_hint(m, &since);
+ if (r <= 0)
+ /* Not idle. Let's check if after a timeout it it might be idle then. */
+ timespec_store(&its.it_value, n + m->idle_action_usec);
+ else {
+ /* Idle! Let's see if it's time to do something, or if
+ * we shall sleep for longer. */
+
+ if (n >= since.monotonic + m->idle_action_usec &&
+ (m->idle_action_not_before_usec <= 0 || n >= m->idle_action_not_before_usec + m->idle_action_usec)) {
+ log_info("System idle. Taking action.");
+
+ manager_handle_action(m, 0, m->idle_action, false, false);
+ m->idle_action_not_before_usec = n;
+ }
+
+ timespec_store(&its.it_value, MAX(since.monotonic, m->idle_action_not_before_usec) + m->idle_action_usec);
+ }
+
+ if (m->idle_action_fd < 0) {
+ struct epoll_event ev;
+
+ m->idle_action_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
+ if (m->idle_action_fd < 0) {
+ log_error("Failed to create idle action timer: %m");
+ r = -errno;
+ goto finish;
+ }
+
+ zero(ev);
+ ev.events = EPOLLIN;
+ ev.data.u32 = FD_IDLE_ACTION;
+
+ if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->idle_action_fd, &ev) < 0) {
+ log_error("Failed to add idle action timer to epoll: %m");
+ r = -errno;
+ goto finish;
+ }
+ }
+
+ if (timerfd_settime(m->idle_action_fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
+ log_error("Failed to reset timerfd: %m");
+ r = -errno;
+ goto finish;
+ }
+
+ return 0;
+
+finish:
+ if (m->idle_action_fd >= 0) {
+ close_nointr_nofail(m->idle_action_fd);
+ m->idle_action_fd = -1;
+ }
+
+ return r;
+}
int manager_startup(Manager *m) {
int r;
Seat *seat;
@@ -1506,6 +1588,8 @@ int manager_startup(Manager *m) {
HASHMAP_FOREACH(inhibitor, m->inhibitors, i)
inhibitor_start(inhibitor);
+ manager_dispatch_idle_action(m);
+
return 0;
}
@@ -1589,6 +1673,10 @@ int manager_run(Manager *m) {
manager_dispatch_console(m);
break;
+ case FD_IDLE_ACTION:
+ manager_dispatch_idle_action(m);
+ break;
+
case FD_BUS:
bus_loop_dispatch(m->bus_fd);
break;