timer.c revision 74051b9b5865586bf4d30b9075649af838fb92bd
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok This file is part of systemd.
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok Copyright 2010 Lennart Poettering
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok systemd is free software; you can redistribute it and/or modify it
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok under the terms of the GNU Lesser General Public License as published by
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok the Free Software Foundation; either version 2.1 of the License, or
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok (at your option) any later version.
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok systemd is distributed in the hope that it will be useful, but
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok WITHOUT ANY WARRANTY; without even the implied warranty of
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok Lesser General Public License for more details.
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok You should have received a copy of the GNU Lesser General Public License
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok along with systemd; If not, see <http://www.gnu.org/licenses/>.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic void timer_init(Unit *u) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert(u->load_state == UNIT_STUB);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek t->next_elapse_monotonic = (usec_t) -1;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek t->next_elapse_realtime = (usec_t) -1;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek watch_init(&t->monotonic_watch);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekvoid timer_free_values(Timer *t) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek while ((v = t->values)) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek LIST_REMOVE(TimerValue, value, t->values, v);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek calendar_spec_free(v->calendar_spec);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic void timer_done(Unit *u) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek unit_unwatch_timer(u, &t->monotonic_watch);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek unit_unwatch_timer(u, &t->realtime_watch);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic int timer_verify(Timer *t) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (UNIT(t)->load_state != UNIT_LOADED)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "%s lacks value setting. Refusing.", UNIT(t)->id);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic int timer_add_default_dependencies(Timer *t) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
12b42c76672a66c2d4ea7212c14f8f1b5a62b78dTom Gundersen return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek r = unit_load_fragment_and_dropin(u);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (u->load_state == UNIT_LOADED) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek r = unit_load_related_unit(u, ".service", &x);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(t->unit), true);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (UNIT(t)->default_dependencies) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek r = timer_add_default_dependencies(t);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic void timer_dump(Unit *u, FILE *f, const char *prefix) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "%sTimer State: %s\n"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "%sResult: %s\n"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek prefix, timer_state_to_string(t->state),
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek prefix, timer_result_to_string(t->result),
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek prefix, UNIT_DEREF(t->unit)->id);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek LIST_FOREACH(value, v, t->values) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (v->base == TIMER_CALENDAR) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek calendar_spec_to_string(v->calendar_spec, &p);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek char timespan1[FORMAT_TIMESPAN_MAX];
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek strna(format_timespan(timespan1, sizeof(timespan1), v->value)));
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic void timer_set_state(Timer *t, TimerState state) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek unit_unwatch_timer(UNIT(t), &t->monotonic_watch);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek unit_unwatch_timer(UNIT(t), &t->realtime_watch);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "%s changed %s -> %s", UNIT(t)->id,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek timer_state_to_string(old_state),
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic void timer_enter_waiting(Timer *t, bool initial);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic int timer_coldplug(Unit *u) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (t->deserialized_state != t->state) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (t->deserialized_state == TIMER_WAITING)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek timer_set_state(t, t->deserialized_state);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic void timer_enter_dead(Timer *t, TimerResult f) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic void timer_enter_waiting(Timer *t, bool initial) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek bool found_monotonic = false, found_realtime = false;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek t->next_elapse_monotonic = t->next_elapse_realtime = 0;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek LIST_FOREACH(value, v, t->values) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (v->base == TIMER_CALENDAR) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek r = calendar_spec_next_usec(v->calendar_spec, ts.realtime, &v->next_elapse);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (!initial && v->next_elapse < ts.realtime) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek t->next_elapse_realtime = v->next_elapse;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (state_translation_table[t->state] == UNIT_ACTIVE)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek base = UNIT(t)->inactive_exit_timestamp.monotonic;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* CLOCK_MONOTONIC equals the uptime on Linux */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek base = UNIT(t)->manager->userspace_timestamp.monotonic;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic <= 0)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek base = UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic <= 0)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek base = UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert_not_reached("Unknown timer base");
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek v->next_elapse = base + v->value;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (!initial && v->next_elapse < ts.monotonic) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek t->next_elapse_monotonic = v->next_elapse;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek t->next_elapse_monotonic = MIN(t->next_elapse_monotonic, v->next_elapse);
83fdc450aa8f79941bec84488ffd5bf8eadab18eAuke Kok log_debug_unit(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
if (found_monotonic) {
format_timespan(buf, sizeof(buf), t->next_elapse_monotonic > ts.monotonic ? t->next_elapse_monotonic - ts.monotonic : 0));
r = unit_watch_timer(UNIT(t), CLOCK_MONOTONIC, false, t->next_elapse_monotonic, &t->monotonic_watch);
goto fail;
if (found_realtime) {
goto fail;
fail:
assert(t);
r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_DEREF(t->unit), JOB_REPLACE, true, &error, NULL);
goto fail;
fail:
assert(t);
return -ENOENT;
timer_enter_waiting(t, true);
assert(t);
assert(u);
assert(f);
assert(u);
if (state < 0)
TimerResult f;
else if (f != TIMER_SUCCESS)
t->result = f;
assert(u);
assert(u);
assert(t);
Iterator i;
Unit *k;
Timer *t;
TimerValue *v;
t = TIMER(k);
v->disabled = false;
switch (t->state) {
case TIMER_WAITING:
case TIMER_ELAPSED:
timer_enter_waiting(t, false);
case TIMER_RUNNING:
timer_enter_waiting(t, false);
case TIMER_DEAD:
case TIMER_FAILED:
assert(t);
assert(u);
timer_enter_waiting(t, false);
.sections =