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 "bus-errors.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);
76 unit_ref_unset(&t->unit);
79 static int timer_verify(Timer *t) {
82 if (UNIT(t)->load_state != UNIT_LOADED)
86 log_error_unit(UNIT(t)->id,
87 "%s lacks value setting. Refusing.", UNIT(t)->id);
94 static int timer_add_default_dependencies(Timer *t) {
99 if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
100 r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true);
104 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
109 return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
112 static int timer_load(Unit *u) {
117 assert(u->load_state == UNIT_STUB);
119 r = unit_load_fragment_and_dropin(u);
123 if (u->load_state == UNIT_LOADED) {
125 if (!UNIT_DEREF(t->unit)) {
128 r = unit_load_related_unit(u, ".service", &x);
132 unit_ref_set(&t->unit, x);
135 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(t->unit), true);
139 if (UNIT(t)->default_dependencies) {
140 r = timer_add_default_dependencies(t);
146 return timer_verify(t);
149 static void timer_dump(Unit *u, FILE *f, const char *prefix) {
154 "%sTimer State: %s\n"
157 prefix, timer_state_to_string(t->state),
158 prefix, timer_result_to_string(t->result),
159 prefix, UNIT_DEREF(t->unit)->id);
161 LIST_FOREACH(value, v, t->values) {
163 if (v->base == TIMER_CALENDAR) {
164 _cleanup_free_ char *p = NULL;
166 calendar_spec_to_string(v->calendar_spec, &p);
171 timer_base_to_string(v->base),
174 char timespan1[FORMAT_TIMESPAN_MAX];
179 timer_base_to_string(v->base),
180 strna(format_timespan(timespan1, sizeof(timespan1), v->value)));
185 static void timer_set_state(Timer *t, TimerState state) {
186 TimerState old_state;
189 old_state = t->state;
192 if (state != TIMER_WAITING) {
193 unit_unwatch_timer(UNIT(t), &t->monotonic_watch);
194 unit_unwatch_timer(UNIT(t), &t->realtime_watch);
197 if (state != old_state)
198 log_debug_unit(UNIT(t)->id,
199 "%s changed %s -> %s", UNIT(t)->id,
200 timer_state_to_string(old_state),
201 timer_state_to_string(state));
203 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
206 static void timer_enter_waiting(Timer *t, bool initial);
208 static int timer_coldplug(Unit *u) {
212 assert(t->state == TIMER_DEAD);
214 if (t->deserialized_state != t->state) {
216 if (t->deserialized_state == TIMER_WAITING)
217 timer_enter_waiting(t, false);
219 timer_set_state(t, t->deserialized_state);
225 static void timer_enter_dead(Timer *t, TimerResult f) {
228 if (f != TIMER_SUCCESS)
231 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
234 static void timer_enter_waiting(Timer *t, bool initial) {
238 bool found_monotonic = false, found_realtime = false;
241 dual_timestamp_get(&ts);
242 t->next_elapse_monotonic = t->next_elapse_realtime = 0;
244 LIST_FOREACH(value, v, t->values) {
249 if (v->base == TIMER_CALENDAR) {
251 r = calendar_spec_next_usec(v->calendar_spec, ts.realtime, &v->next_elapse);
255 if (!initial && v->next_elapse < ts.realtime) {
261 t->next_elapse_realtime = v->next_elapse;
263 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
265 found_realtime = true;
271 if (state_translation_table[t->state] == UNIT_ACTIVE)
272 base = UNIT(t)->inactive_exit_timestamp.monotonic;
278 /* CLOCK_MONOTONIC equals the uptime on Linux */
283 base = UNIT(t)->manager->userspace_timestamp.monotonic;
286 case TIMER_UNIT_ACTIVE:
288 if (UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic <= 0)
291 base = UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic;
294 case TIMER_UNIT_INACTIVE:
296 if (UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic <= 0)
299 base = UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic;
303 assert_not_reached("Unknown timer base");
306 v->next_elapse = base + v->value;
308 if (!initial && v->next_elapse < ts.monotonic) {
313 if (!found_monotonic)
314 t->next_elapse_monotonic = v->next_elapse;
316 t->next_elapse_monotonic = MIN(t->next_elapse_monotonic, v->next_elapse);
318 found_monotonic = true;
322 if (!found_monotonic && !found_realtime) {
323 log_debug_unit(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
324 timer_set_state(t, TIMER_ELAPSED);
328 if (found_monotonic) {
329 char buf[FORMAT_TIMESPAN_MAX];
330 log_debug_unit(UNIT(t)->id,
331 "%s: Monotonic timer elapses in %s the next time.",
333 format_timespan(buf, sizeof(buf), t->next_elapse_monotonic > ts.monotonic ? t->next_elapse_monotonic - ts.monotonic : 0));
335 r = unit_watch_timer(UNIT(t), CLOCK_MONOTONIC, false, t->next_elapse_monotonic, &t->monotonic_watch);
339 unit_unwatch_timer(UNIT(t), &t->monotonic_watch);
341 if (found_realtime) {
342 char buf[FORMAT_TIMESTAMP_MAX];
343 log_debug_unit(UNIT(t)->id,
344 "%s: Realtime timer elapses at %s the next time.",
346 format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
348 r = unit_watch_timer(UNIT(t), CLOCK_REALTIME, false, t->next_elapse_realtime, &t->realtime_watch);
352 unit_unwatch_timer(UNIT(t), &t->realtime_watch);
354 timer_set_state(t, TIMER_WAITING);
358 log_warning_unit(UNIT(t)->id,
359 "%s failed to enter waiting state: %s",
360 UNIT(t)->id, strerror(-r));
361 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
364 static void timer_enter_running(Timer *t) {
369 dbus_error_init(&error);
371 /* Don't start job if we are supposed to go down */
372 if (UNIT(t)->job && UNIT(t)->job->type == JOB_STOP)
375 r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_DEREF(t->unit), JOB_REPLACE, true, &error, NULL);
379 timer_set_state(t, TIMER_RUNNING);
383 log_warning_unit(UNIT(t)->id,
384 "%s failed to queue unit startup job: %s",
385 UNIT(t)->id, bus_error(&error, r));
386 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
388 dbus_error_free(&error);
391 static int timer_start(Unit *u) {
395 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
397 if (UNIT_DEREF(t->unit)->load_state != UNIT_LOADED)
400 t->result = TIMER_SUCCESS;
401 timer_enter_waiting(t, true);
405 static int timer_stop(Unit *u) {
409 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
411 timer_enter_dead(t, TIMER_SUCCESS);
415 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
422 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
423 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
428 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
436 if (streq(key, "state")) {
439 state = timer_state_from_string(value);
441 log_debug_unit(u->id, "Failed to parse state value %s", value);
443 t->deserialized_state = state;
444 } else if (streq(key, "result")) {
447 f = timer_result_from_string(value);
449 log_debug_unit(u->id, "Failed to parse result value %s", value);
450 else if (f != TIMER_SUCCESS)
454 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
459 static UnitActiveState timer_active_state(Unit *u) {
462 return state_translation_table[TIMER(u)->state];
465 static const char *timer_sub_state_to_string(Unit *u) {
468 return timer_state_to_string(TIMER(u)->state);
471 static void timer_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
475 assert(elapsed == 1);
477 if (t->state != TIMER_WAITING)
480 log_debug_unit(u->id, "Timer elapsed on %s", u->id);
481 timer_enter_running(t);
484 void timer_unit_notify(Unit *u, UnitActiveState new_state) {
488 if (u->type == UNIT_TIMER)
491 SET_FOREACH(k, u->dependencies[UNIT_TRIGGERED_BY], i) {
495 if (k->type != UNIT_TIMER)
498 if (k->load_state != UNIT_LOADED)
503 /* Reenable all timers that depend on unit state */
504 LIST_FOREACH(value, v, t->values)
505 if (v->base == TIMER_UNIT_ACTIVE ||
506 v->base == TIMER_UNIT_INACTIVE)
514 /* Recalculate sleep time */
515 timer_enter_waiting(t, false);
520 if (UNIT_IS_INACTIVE_OR_FAILED(new_state)) {
521 log_debug_unit(UNIT(t)->id,
522 "%s got notified about unit deactivation.",
524 timer_enter_waiting(t, false);
534 assert_not_reached("Unknown timer state");
539 static void timer_reset_failed(Unit *u) {
544 if (t->state == TIMER_FAILED)
545 timer_set_state(t, TIMER_DEAD);
547 t->result = TIMER_SUCCESS;
550 static void timer_time_change(Unit *u) {
555 if (t->state != TIMER_WAITING)
559 "%s: time change, recalculating next elapse.", u->id);
560 timer_enter_waiting(t, false);
563 static const char* const timer_state_table[_TIMER_STATE_MAX] = {
564 [TIMER_DEAD] = "dead",
565 [TIMER_WAITING] = "waiting",
566 [TIMER_RUNNING] = "running",
567 [TIMER_ELAPSED] = "elapsed",
568 [TIMER_FAILED] = "failed"
571 DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
573 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
574 [TIMER_ACTIVE] = "OnActiveSec",
575 [TIMER_BOOT] = "OnBootSec",
576 [TIMER_STARTUP] = "OnStartupSec",
577 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
578 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
579 [TIMER_CALENDAR] = "OnCalendar"
582 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
584 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
585 [TIMER_SUCCESS] = "success",
586 [TIMER_FAILURE_RESOURCES] = "resources"
589 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
591 const UnitVTable timer_vtable = {
592 .object_size = sizeof(Timer),
602 .coldplug = timer_coldplug,
606 .start = timer_start,
609 .serialize = timer_serialize,
610 .deserialize_item = timer_deserialize_item,
612 .active_state = timer_active_state,
613 .sub_state_to_string = timer_sub_state_to_string,
615 .timer_event = timer_timer_event,
617 .reset_failed = timer_reset_failed,
618 .time_change = timer_time_change,
620 .bus_interface = "org.freedesktop.systemd1.Timer",
621 .bus_message_handler = bus_timer_message_handler,
622 .bus_invalidating_properties = bus_timer_invalidating_properties