1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "unit-name.h"
27 #include "dbus-timer.h"
29 #include "dbus-common.h"
31 static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
32 [TIMER_DEAD] = UNIT_INACTIVE,
33 [TIMER_WAITING] = UNIT_ACTIVE,
34 [TIMER_RUNNING] = UNIT_ACTIVE,
35 [TIMER_ELAPSED] = UNIT_ACTIVE,
36 [TIMER_FAILED] = UNIT_FAILED
39 static void timer_init(Unit *u) {
43 assert(u->load_state == UNIT_STUB);
45 t->next_elapse_monotonic = (usec_t) -1;
46 t->next_elapse_realtime = (usec_t) -1;
47 watch_init(&t->monotonic_watch);
48 watch_init(&t->realtime_watch);
51 void timer_free_values(Timer *t) {
56 while ((v = t->values)) {
57 LIST_REMOVE(TimerValue, value, t->values, v);
60 calendar_spec_free(v->calendar_spec);
66 static void timer_done(Unit *u) {
73 unit_unwatch_timer(u, &t->monotonic_watch);
74 unit_unwatch_timer(u, &t->realtime_watch);
77 static int timer_verify(Timer *t) {
80 if (UNIT(t)->load_state != UNIT_LOADED)
84 log_error_unit(UNIT(t)->id,
85 "%s lacks value setting. Refusing.", UNIT(t)->id);
92 static int timer_add_default_dependencies(Timer *t) {
97 r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
101 if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
102 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
107 return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
110 static int timer_load(Unit *u) {
115 assert(u->load_state == UNIT_STUB);
117 r = unit_load_fragment_and_dropin(u);
121 if (u->load_state == UNIT_LOADED) {
123 if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
126 r = unit_load_related_unit(u, ".service", &x);
130 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
135 if (UNIT(t)->default_dependencies) {
136 r = timer_add_default_dependencies(t);
142 return timer_verify(t);
145 static void timer_dump(Unit *u, FILE *f, const char *prefix) {
150 trigger = UNIT_TRIGGER(u);
153 "%sTimer State: %s\n"
156 prefix, timer_state_to_string(t->state),
157 prefix, timer_result_to_string(t->result),
158 prefix, trigger ? trigger->id : "n/a");
160 LIST_FOREACH(value, v, t->values) {
162 if (v->base == TIMER_CALENDAR) {
163 _cleanup_free_ char *p = NULL;
165 calendar_spec_to_string(v->calendar_spec, &p);
170 timer_base_to_string(v->base),
173 char timespan1[FORMAT_TIMESPAN_MAX];
178 timer_base_to_string(v->base),
179 strna(format_timespan(timespan1, sizeof(timespan1), v->value, 0)));
184 static void timer_set_state(Timer *t, TimerState state) {
185 TimerState old_state;
188 old_state = t->state;
191 if (state != TIMER_WAITING) {
192 unit_unwatch_timer(UNIT(t), &t->monotonic_watch);
193 unit_unwatch_timer(UNIT(t), &t->realtime_watch);
196 if (state != old_state)
197 log_debug_unit(UNIT(t)->id,
198 "%s changed %s -> %s", UNIT(t)->id,
199 timer_state_to_string(old_state),
200 timer_state_to_string(state));
202 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
205 static void timer_enter_waiting(Timer *t, bool initial);
207 static int timer_coldplug(Unit *u) {
211 assert(t->state == TIMER_DEAD);
213 if (t->deserialized_state != t->state) {
215 if (t->deserialized_state == TIMER_WAITING)
216 timer_enter_waiting(t, false);
218 timer_set_state(t, t->deserialized_state);
224 static void timer_enter_dead(Timer *t, TimerResult f) {
227 if (f != TIMER_SUCCESS)
230 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
233 static void timer_enter_waiting(Timer *t, bool initial) {
237 bool found_monotonic = false, found_realtime = false;
240 dual_timestamp_get(&ts);
241 t->next_elapse_monotonic = t->next_elapse_realtime = 0;
243 LIST_FOREACH(value, v, t->values) {
248 if (v->base == TIMER_CALENDAR) {
250 r = calendar_spec_next_usec(v->calendar_spec, ts.realtime, &v->next_elapse);
255 t->next_elapse_realtime = v->next_elapse;
257 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
259 found_realtime = true;
265 if (state_translation_table[t->state] == UNIT_ACTIVE)
266 base = UNIT(t)->inactive_exit_timestamp.monotonic;
272 /* CLOCK_MONOTONIC equals the uptime on Linux */
277 base = UNIT(t)->manager->userspace_timestamp.monotonic;
280 case TIMER_UNIT_ACTIVE:
282 base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
285 base = t->last_trigger_monotonic;
292 case TIMER_UNIT_INACTIVE:
294 base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
297 base = t->last_trigger_monotonic;
305 assert_not_reached("Unknown timer base");
308 v->next_elapse = base + v->value;
311 v->next_elapse < ts.monotonic &&
312 (v->base == TIMER_ACTIVE || v->base == TIMER_BOOT || v->base == TIMER_STARTUP)) {
313 /* This is a one time trigger, disable it now */
318 if (!found_monotonic)
319 t->next_elapse_monotonic = v->next_elapse;
321 t->next_elapse_monotonic = MIN(t->next_elapse_monotonic, v->next_elapse);
323 found_monotonic = true;
327 if (!found_monotonic && !found_realtime) {
328 log_debug_unit(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
329 timer_set_state(t, TIMER_ELAPSED);
333 if (found_monotonic) {
334 char buf[FORMAT_TIMESPAN_MAX];
335 log_debug_unit(UNIT(t)->id,
336 "%s: Monotonic timer elapses in %s.",
338 format_timespan(buf, sizeof(buf), t->next_elapse_monotonic > ts.monotonic ? t->next_elapse_monotonic - ts.monotonic : 0, 0));
340 r = unit_watch_timer(UNIT(t), CLOCK_MONOTONIC, false, t->next_elapse_monotonic, &t->monotonic_watch);
344 unit_unwatch_timer(UNIT(t), &t->monotonic_watch);
346 if (found_realtime) {
347 char buf[FORMAT_TIMESTAMP_MAX];
348 log_debug_unit(UNIT(t)->id,
349 "%s: Realtime timer elapses at %s.",
351 format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
353 r = unit_watch_timer(UNIT(t), CLOCK_REALTIME, false, t->next_elapse_realtime, &t->realtime_watch);
357 unit_unwatch_timer(UNIT(t), &t->realtime_watch);
359 timer_set_state(t, TIMER_WAITING);
363 log_warning_unit(UNIT(t)->id,
364 "%s failed to enter waiting state: %s",
365 UNIT(t)->id, strerror(-r));
366 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
369 static void timer_enter_running(Timer *t) {
374 dbus_error_init(&error);
376 /* Don't start job if we are supposed to go down */
377 if (unit_stop_pending(UNIT(t)))
380 r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
381 JOB_REPLACE, true, &error, NULL);
385 t->last_trigger_monotonic = now(CLOCK_MONOTONIC);
387 timer_set_state(t, TIMER_RUNNING);
391 log_warning_unit(UNIT(t)->id,
392 "%s failed to queue unit startup job: %s",
393 UNIT(t)->id, bus_error(&error, r));
394 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
396 dbus_error_free(&error);
399 static int timer_start(Unit *u) {
403 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
405 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
408 t->result = TIMER_SUCCESS;
409 timer_enter_waiting(t, true);
413 static int timer_stop(Unit *u) {
417 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
419 timer_enter_dead(t, TIMER_SUCCESS);
423 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
430 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
431 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
436 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
444 if (streq(key, "state")) {
447 state = timer_state_from_string(value);
449 log_debug_unit(u->id, "Failed to parse state value %s", value);
451 t->deserialized_state = state;
452 } else if (streq(key, "result")) {
455 f = timer_result_from_string(value);
457 log_debug_unit(u->id, "Failed to parse result value %s", value);
458 else if (f != TIMER_SUCCESS)
462 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
467 _pure_ static UnitActiveState timer_active_state(Unit *u) {
470 return state_translation_table[TIMER(u)->state];
473 _pure_ static const char *timer_sub_state_to_string(Unit *u) {
476 return timer_state_to_string(TIMER(u)->state);
479 static void timer_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
483 assert(elapsed == 1);
485 if (t->state != TIMER_WAITING)
488 log_debug_unit(u->id, "Timer elapsed on %s", u->id);
489 timer_enter_running(t);
492 static void timer_trigger_notify(Unit *u, Unit *other) {
499 if (other->load_state != UNIT_LOADED)
502 /* Reenable all timers that depend on unit state */
503 LIST_FOREACH(value, v, t->values)
504 if (v->base == TIMER_UNIT_ACTIVE ||
505 v->base == TIMER_UNIT_INACTIVE)
513 /* Recalculate sleep time */
514 timer_enter_waiting(t, false);
519 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
520 log_debug_unit(UNIT(t)->id,
521 "%s got notified about unit deactivation.",
523 timer_enter_waiting(t, false);
532 assert_not_reached("Unknown timer state");
536 static void timer_reset_failed(Unit *u) {
541 if (t->state == TIMER_FAILED)
542 timer_set_state(t, TIMER_DEAD);
544 t->result = TIMER_SUCCESS;
547 static void timer_time_change(Unit *u) {
552 if (t->state != TIMER_WAITING)
555 log_debug_unit(u->id,
556 "%s: time change, recalculating next elapse.", u->id);
557 timer_enter_waiting(t, false);
560 static const char* const timer_state_table[_TIMER_STATE_MAX] = {
561 [TIMER_DEAD] = "dead",
562 [TIMER_WAITING] = "waiting",
563 [TIMER_RUNNING] = "running",
564 [TIMER_ELAPSED] = "elapsed",
565 [TIMER_FAILED] = "failed"
568 DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
570 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
571 [TIMER_ACTIVE] = "OnActiveSec",
572 [TIMER_BOOT] = "OnBootSec",
573 [TIMER_STARTUP] = "OnStartupSec",
574 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
575 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
576 [TIMER_CALENDAR] = "OnCalendar"
579 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
581 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
582 [TIMER_SUCCESS] = "success",
583 [TIMER_FAILURE_RESOURCES] = "resources"
586 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
588 const UnitVTable timer_vtable = {
589 .object_size = sizeof(Timer),
599 .coldplug = timer_coldplug,
603 .start = timer_start,
606 .serialize = timer_serialize,
607 .deserialize_item = timer_deserialize_item,
609 .active_state = timer_active_state,
610 .sub_state_to_string = timer_sub_state_to_string,
612 .timer_event = timer_timer_event,
614 .trigger_notify = timer_trigger_notify,
616 .reset_failed = timer_reset_failed,
617 .time_change = timer_time_change,
619 .bus_interface = "org.freedesktop.systemd1.Timer",
620 .bus_message_handler = bus_timer_message_handler,
621 .bus_invalidating_properties = bus_timer_invalidating_properties