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"
30 #include "bus-error.h"
32 static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
33 [TIMER_DEAD] = UNIT_INACTIVE,
34 [TIMER_WAITING] = UNIT_ACTIVE,
35 [TIMER_RUNNING] = UNIT_ACTIVE,
36 [TIMER_ELAPSED] = UNIT_ACTIVE,
37 [TIMER_FAILED] = UNIT_FAILED
40 static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata);
42 static void timer_init(Unit *u) {
46 assert(u->load_state == UNIT_STUB);
48 t->next_elapse_monotonic = (usec_t) -1;
49 t->next_elapse_realtime = (usec_t) -1;
52 void timer_free_values(Timer *t) {
57 while ((v = t->values)) {
58 LIST_REMOVE(value, t->values, v);
61 calendar_spec_free(v->calendar_spec);
67 static void timer_done(Unit *u) {
74 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
75 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
78 static int timer_verify(Timer *t) {
81 if (UNIT(t)->load_state != UNIT_LOADED)
85 log_error_unit(UNIT(t)->id,
86 "%s lacks value setting. Refusing.", UNIT(t)->id);
93 static int timer_add_default_dependencies(Timer *t) {
98 r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
102 if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
103 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
108 return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
111 static int timer_load(Unit *u) {
116 assert(u->load_state == UNIT_STUB);
118 r = unit_load_fragment_and_dropin(u);
122 if (u->load_state == UNIT_LOADED) {
124 if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
127 r = unit_load_related_unit(u, ".service", &x);
131 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
136 if (UNIT(t)->default_dependencies) {
137 r = timer_add_default_dependencies(t);
143 return timer_verify(t);
146 static void timer_dump(Unit *u, FILE *f, const char *prefix) {
151 trigger = UNIT_TRIGGER(u);
154 "%sTimer State: %s\n"
157 prefix, timer_state_to_string(t->state),
158 prefix, timer_result_to_string(t->result),
159 prefix, trigger ? trigger->id : "n/a");
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, 0)));
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 t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
194 t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
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);
235 static void timer_enter_waiting(Timer *t, bool initial) {
239 bool found_monotonic = false, found_realtime = false;
242 dual_timestamp_get(&ts);
243 t->next_elapse_monotonic = t->next_elapse_realtime = 0;
245 LIST_FOREACH(value, v, t->values) {
250 if (v->base == TIMER_CALENDAR) {
252 r = calendar_spec_next_usec(v->calendar_spec, ts.realtime, &v->next_elapse);
257 t->next_elapse_realtime = v->next_elapse;
259 t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
261 found_realtime = true;
267 if (state_translation_table[t->state] == UNIT_ACTIVE)
268 base = UNIT(t)->inactive_exit_timestamp.monotonic;
274 /* CLOCK_MONOTONIC equals the uptime on Linux */
279 base = UNIT(t)->manager->userspace_timestamp.monotonic;
282 case TIMER_UNIT_ACTIVE:
284 base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
287 base = t->last_trigger_monotonic;
294 case TIMER_UNIT_INACTIVE:
296 base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
299 base = t->last_trigger_monotonic;
307 assert_not_reached("Unknown timer base");
310 v->next_elapse = base + v->value;
313 v->next_elapse < ts.monotonic &&
314 (v->base == TIMER_ACTIVE || v->base == TIMER_BOOT || v->base == TIMER_STARTUP)) {
315 /* This is a one time trigger, disable it now */
320 if (!found_monotonic)
321 t->next_elapse_monotonic = v->next_elapse;
323 t->next_elapse_monotonic = MIN(t->next_elapse_monotonic, v->next_elapse);
325 found_monotonic = true;
329 if (!found_monotonic && !found_realtime) {
330 log_debug_unit(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
331 timer_set_state(t, TIMER_ELAPSED);
335 if (found_monotonic) {
336 char buf[FORMAT_TIMESPAN_MAX];
337 log_debug_unit(UNIT(t)->id,
338 "%s: Monotonic timer elapses in %s.",
340 format_timespan(buf, sizeof(buf), t->next_elapse_monotonic > ts.monotonic ? t->next_elapse_monotonic - ts.monotonic : 0, 0));
342 if (t->monotonic_event_source) {
343 r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic);
347 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
349 r = sd_event_add_monotonic(UNIT(t)->manager->event, t->next_elapse_monotonic, 0, timer_dispatch, t, &t->monotonic_event_source);
354 } else if (t->monotonic_event_source) {
355 r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
361 if (found_realtime) {
362 char buf[FORMAT_TIMESTAMP_MAX];
363 log_debug_unit(UNIT(t)->id,
364 "%s: Realtime timer elapses at %s.",
366 format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
368 if (t->realtime_event_source) {
369 r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
373 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
375 r = sd_event_add_realtime(UNIT(t)->manager->event, t->next_elapse_realtime, 0, timer_dispatch, t, &t->realtime_event_source);
380 } else if (t->realtime_event_source) {
381 r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
387 timer_set_state(t, TIMER_WAITING);
391 log_warning_unit(UNIT(t)->id,
392 "%s failed to enter waiting state: %s",
393 UNIT(t)->id, strerror(-r));
394 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
397 static void timer_enter_running(Timer *t) {
398 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
403 /* Don't start job if we are supposed to go down */
404 if (unit_stop_pending(UNIT(t)))
407 r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
408 JOB_REPLACE, true, &error, NULL);
412 t->last_trigger_monotonic = now(CLOCK_MONOTONIC);
414 timer_set_state(t, TIMER_RUNNING);
418 log_warning_unit(UNIT(t)->id,
419 "%s failed to queue unit startup job: %s",
420 UNIT(t)->id, bus_error_message(&error, r));
421 timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
424 static int timer_start(Unit *u) {
428 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
430 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
433 t->result = TIMER_SUCCESS;
434 timer_enter_waiting(t, true);
438 static int timer_stop(Unit *u) {
442 assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
444 timer_enter_dead(t, TIMER_SUCCESS);
448 static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
455 unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
456 unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
461 static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
469 if (streq(key, "state")) {
472 state = timer_state_from_string(value);
474 log_debug_unit(u->id, "Failed to parse state value %s", value);
476 t->deserialized_state = state;
477 } else if (streq(key, "result")) {
480 f = timer_result_from_string(value);
482 log_debug_unit(u->id, "Failed to parse result value %s", value);
483 else if (f != TIMER_SUCCESS)
487 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
492 _pure_ static UnitActiveState timer_active_state(Unit *u) {
495 return state_translation_table[TIMER(u)->state];
498 _pure_ static const char *timer_sub_state_to_string(Unit *u) {
501 return timer_state_to_string(TIMER(u)->state);
504 static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
505 Timer *t = TIMER(userdata);
509 if (t->state != TIMER_WAITING)
512 log_debug_unit(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id);
513 timer_enter_running(t);
517 static void timer_trigger_notify(Unit *u, Unit *other) {
524 if (other->load_state != UNIT_LOADED)
527 /* Reenable all timers that depend on unit state */
528 LIST_FOREACH(value, v, t->values)
529 if (v->base == TIMER_UNIT_ACTIVE ||
530 v->base == TIMER_UNIT_INACTIVE)
538 /* Recalculate sleep time */
539 timer_enter_waiting(t, false);
544 if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
545 log_debug_unit(UNIT(t)->id,
546 "%s got notified about unit deactivation.",
548 timer_enter_waiting(t, false);
557 assert_not_reached("Unknown timer state");
561 static void timer_reset_failed(Unit *u) {
566 if (t->state == TIMER_FAILED)
567 timer_set_state(t, TIMER_DEAD);
569 t->result = TIMER_SUCCESS;
572 static void timer_time_change(Unit *u) {
577 if (t->state != TIMER_WAITING)
580 log_debug_unit(u->id,
581 "%s: time change, recalculating next elapse.", u->id);
582 timer_enter_waiting(t, false);
585 static const char* const timer_state_table[_TIMER_STATE_MAX] = {
586 [TIMER_DEAD] = "dead",
587 [TIMER_WAITING] = "waiting",
588 [TIMER_RUNNING] = "running",
589 [TIMER_ELAPSED] = "elapsed",
590 [TIMER_FAILED] = "failed"
593 DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
595 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
596 [TIMER_ACTIVE] = "OnActiveSec",
597 [TIMER_BOOT] = "OnBootSec",
598 [TIMER_STARTUP] = "OnStartupSec",
599 [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
600 [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
601 [TIMER_CALENDAR] = "OnCalendar"
604 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
606 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
607 [TIMER_SUCCESS] = "success",
608 [TIMER_FAILURE_RESOURCES] = "resources"
611 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
613 const UnitVTable timer_vtable = {
614 .object_size = sizeof(Timer),
625 .coldplug = timer_coldplug,
629 .start = timer_start,
632 .serialize = timer_serialize,
633 .deserialize_item = timer_deserialize_item,
635 .active_state = timer_active_state,
636 .sub_state_to_string = timer_sub_state_to_string,
638 .trigger_notify = timer_trigger_notify,
640 .reset_failed = timer_reset_failed,
641 .time_change = timer_time_change,
643 .bus_interface = "org.freedesktop.systemd1.Timer",
644 .bus_vtable = bus_timer_vtable,
645 .bus_changing_properties = bus_timer_changing_properties,