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 = (usec_t) -1;
48 static void timer_done(Unit *u) {
54 while ((v = t->values)) {
55 LIST_REMOVE(TimerValue, value, t->values, v);
59 unit_unwatch_timer(u, &t->timer_watch);
61 unit_ref_unset(&t->unit);
64 static int timer_verify(Timer *t) {
67 if (UNIT(t)->load_state != UNIT_LOADED)
71 log_error("%s lacks value setting. Refusing.", UNIT(t)->id);
78 static int timer_add_default_dependencies(Timer *t) {
83 if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
84 if ((r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
87 if ((r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
91 return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
94 static int timer_load(Unit *u) {
99 assert(u->load_state == UNIT_STUB);
101 if ((r = unit_load_fragment_and_dropin(u)) < 0)
104 if (u->load_state == UNIT_LOADED) {
106 if (!UNIT_DEREF(t->unit)) {
109 r = unit_load_related_unit(u, ".service", &x);
113 unit_ref_set(&t->unit, x);
116 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(t->unit), true);
120 if (UNIT(t)->default_dependencies)
121 if ((r = timer_add_default_dependencies(t)) < 0)
125 return timer_verify(t);
128 static void timer_dump(Unit *u, FILE *f, const char *prefix) {
132 timespan1[FORMAT_TIMESPAN_MAX];
135 "%sTimer State: %s\n"
138 prefix, timer_state_to_string(t->state),
139 prefix, timer_result_to_string(t->result),
140 prefix, UNIT_DEREF(t->unit)->id);
142 LIST_FOREACH(value, v, t->values)
146 timer_base_to_string(v->base),
147 strna(format_timespan(timespan1, sizeof(timespan1), v->value)));
150 static void timer_set_state(Timer *t, TimerState state) {
151 TimerState old_state;
154 old_state = t->state;
157 if (state != TIMER_WAITING)
158 unit_unwatch_timer(UNIT(t), &t->timer_watch);
160 if (state != old_state)
161 log_debug("%s changed %s -> %s",
163 timer_state_to_string(old_state),
164 timer_state_to_string(state));
166 unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
169 static void timer_enter_waiting(Timer *t, bool initial);
171 static int timer_coldplug(Unit *u) {
175 assert(t->state == TIMER_DEAD);
177 if (t->deserialized_state != t->state) {
179 if (t->deserialized_state == TIMER_WAITING)
180 timer_enter_waiting(t, false);
182 timer_set_state(t, t->deserialized_state);
188 static void timer_enter_dead(Timer *t, TimerResult f) {
191 if (f != TIMER_SUCCESS)
194 timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
197 static void timer_enter_waiting(Timer *t, bool initial) {
199 usec_t base = 0, delay, n;
203 n = now(CLOCK_MONOTONIC);
205 LIST_FOREACH(value, v, t->values) {
213 if (state_translation_table[t->state] == UNIT_ACTIVE)
214 base = UNIT(t)->inactive_exit_timestamp.monotonic;
220 /* CLOCK_MONOTONIC equals the uptime on Linux */
225 base = UNIT(t)->manager->startup_timestamp.monotonic;
228 case TIMER_UNIT_ACTIVE:
230 if (UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic <= 0)
233 base = UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic;
236 case TIMER_UNIT_INACTIVE:
238 if (UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic <= 0)
241 base = UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic;
245 assert_not_reached("Unknown timer base");
248 v->next_elapse = base + v->value;
250 if (!initial && v->next_elapse < n) {
256 t->next_elapse = v->next_elapse;
258 t->next_elapse = MIN(t->next_elapse, v->next_elapse);
264 timer_set_state(t, TIMER_ELAPSED);
268 delay = n < t->next_elapse ? t->next_elapse - n : 0;
270 if ((r = unit_watch_timer(UNIT(t), delay, &t->timer_watch)) < 0)
273 timer_set_state(t, TIMER_WAITING);
277 log_warning("%s failed to enter waiting state: %s", UNIT(t)->id, strerror(-r));
278 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
281 static void timer_enter_running(Timer *t) {
286 dbus_error_init(&error);
288 /* Don't start job if we are supposed to go down */
289 if (UNIT(t)->job && UNIT(t)->job->type == JOB_STOP)
292 if ((r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_DEREF(t->unit), JOB_REPLACE, true, &error, NULL)) < 0)
295 timer_set_state(t, TIMER_RUNNING);
299 log_warning("%s failed to queue unit startup job: %s", UNIT(t)->id, bus_error(&error, r));
300 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
302 dbus_error_free(&error);
305 static int timer_start(Unit *u) {
309 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
311 if (UNIT_DEREF(t->unit)->load_state != UNIT_LOADED)
314 t->result = TIMER_SUCCESS;
315 timer_enter_waiting(t, true);
319 static int timer_stop(Unit *u) {
323 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
325 timer_enter_dead(t, TIMER_SUCCESS);
329 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
336 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
337 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
342 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
350 if (streq(key, "state")) {
353 if ((state = timer_state_from_string(value)) < 0)
354 log_debug("Failed to parse state value %s", value);
356 t->deserialized_state = state;
357 } else if (streq(key, "result")) {
360 f = timer_result_from_string(value);
362 log_debug("Failed to parse result value %s", value);
363 else if (f != TIMER_SUCCESS)
367 log_debug("Unknown serialization key '%s'", key);
372 static UnitActiveState timer_active_state(Unit *u) {
375 return state_translation_table[TIMER(u)->state];
378 static const char *timer_sub_state_to_string(Unit *u) {
381 return timer_state_to_string(TIMER(u)->state);
384 static void timer_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
388 assert(elapsed == 1);
390 if (t->state != TIMER_WAITING)
393 log_debug("Timer elapsed on %s", u->id);
394 timer_enter_running(t);
397 void timer_unit_notify(Unit *u, UnitActiveState new_state) {
401 if (u->type == UNIT_TIMER)
404 SET_FOREACH(k, u->dependencies[UNIT_TRIGGERED_BY], i) {
408 if (k->type != UNIT_TIMER)
411 if (k->load_state != UNIT_LOADED)
416 /* Reenable all timers that depend on unit state */
417 LIST_FOREACH(value, v, t->values)
418 if (v->base == TIMER_UNIT_ACTIVE ||
419 v->base == TIMER_UNIT_INACTIVE)
427 /* Recalculate sleep time */
428 timer_enter_waiting(t, false);
433 if (UNIT_IS_INACTIVE_OR_FAILED(new_state)) {
434 log_debug("%s got notified about unit deactivation.", UNIT(t)->id);
435 timer_enter_waiting(t, false);
445 assert_not_reached("Unknown timer state");
450 static void timer_reset_failed(Unit *u) {
455 if (t->state == TIMER_FAILED)
456 timer_set_state(t, TIMER_DEAD);
458 t->result = TIMER_SUCCESS;
461 static const char* const timer_state_table[_TIMER_STATE_MAX] = {
462 [TIMER_DEAD] = "dead",
463 [TIMER_WAITING] = "waiting",
464 [TIMER_RUNNING] = "running",
465 [TIMER_ELAPSED] = "elapsed",
466 [TIMER_FAILED] = "failed"
469 DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
471 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
472 [TIMER_ACTIVE] = "OnActiveSec",
473 [TIMER_BOOT] = "OnBootSec",
474 [TIMER_STARTUP] = "OnStartupSec",
475 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
476 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec"
479 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
481 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
482 [TIMER_SUCCESS] = "success",
483 [TIMER_FAILURE_RESOURCES] = "resources"
486 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
488 const UnitVTable timer_vtable = {
489 .object_size = sizeof(Timer),
499 .coldplug = timer_coldplug,
503 .start = timer_start,
506 .serialize = timer_serialize,
507 .deserialize_item = timer_deserialize_item,
509 .active_state = timer_active_state,
510 .sub_state_to_string = timer_sub_state_to_string,
512 .timer_event = timer_timer_event,
514 .reset_failed = timer_reset_failed,
516 .bus_interface = "org.freedesktop.systemd1.Timer",
517 .bus_message_handler = bus_timer_message_handler,
518 .bus_invalidating_properties = bus_timer_invalidating_properties