1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-23 17:34:00 +03:00

core: add RemainAfterElapse= setting to timer units

Previously, after a timer unit elapsed we'd leave it around for good,
which has the nice benefit that starting a timer that shall trigger at a
specific point in time multiple times will only result in one trigger
instead of possibly many. With this change a new option
RemainAfterElapse= is added. It defaults to "true", to mimic the old
behaviour. If set to "false" timer units will be unloaded after they
elapsed. This is specifically useful for transient timer units.
This commit is contained in:
Lennart Poettering 2015-11-17 20:13:36 +01:00
parent df446f9603
commit 3e0c30ac56
5 changed files with 61 additions and 14 deletions

View File

@ -243,6 +243,15 @@
again after any work that is to be done is finished. Defaults
to <varname>false</varname>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>RemainAfterExit=</varname></term>
<listitem><para>Takes a boolean argument. If true, an elapsed
timer will stay loaded, and its state remains
queriable. Defaults to
<varname>yes</varname>.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -182,6 +182,7 @@ const sd_bus_vtable bus_timer_vtable[] = {
SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RemainAfterElapse", "b", bus_property_get_bool, offsetof(Timer, remain_after_elapse), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
@ -283,7 +284,6 @@ static int bus_timer_set_transient_property(
return 1;
} else if (streq(name, "WakeSystem")) {
int b;
r = sd_bus_message_read(message, "b", &b);
@ -292,11 +292,24 @@ static int bus_timer_set_transient_property(
if (mode != UNIT_CHECK) {
t->wake_system = b;
unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(t->wake_system));
unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(b));
}
return 1;
} else if (streq(name, "RemainAfterElapse")) {
int b;
r = sd_bus_message_read(message, "b", &b);
if (r < 0)
return r;
if (mode != UNIT_CHECK) {
t->remain_after_elapse = b;
unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(b));
}
return 1;
}
return 0;

View File

@ -344,6 +344,7 @@ Timer.OnUnitActiveSec, config_parse_timer, 0,
Timer.OnUnitInactiveSec, config_parse_timer, 0, 0
Timer.Persistent, config_parse_bool, 0, offsetof(Timer, persistent)
Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system)
Timer.RemainAfterElapse, config_parse_bool, 0, offsetof(Timer, remain_after_elapse)
Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec)
Timer.Unit, config_parse_trigger_unit, 0, 0
m4_dnl

View File

@ -55,6 +55,7 @@ static void timer_init(Unit *u) {
t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
t->next_elapse_realtime = USEC_INFINITY;
t->accuracy_usec = u->manager->default_timer_accuracy_usec;
t->remain_after_elapse = true;
}
void timer_free_values(Timer *t) {
@ -217,13 +218,15 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) {
"%sUnit: %s\n"
"%sPersistent: %s\n"
"%sWakeSystem: %s\n"
"%sAccuracy: %s\n",
"%sAccuracy: %s\n"
"%sRemainAfterElapse: %s\n",
prefix, timer_state_to_string(t->state),
prefix, timer_result_to_string(t->result),
prefix, trigger ? trigger->id : "n/a",
prefix, yes_no(t->persistent),
prefix, yes_no(t->wake_system),
prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1));
prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1),
prefix, yes_no(t->remain_after_elapse));
LIST_FOREACH(value, v, t->values) {
@ -275,13 +278,13 @@ static int timer_coldplug(Unit *u) {
assert(t);
assert(t->state == TIMER_DEAD);
if (t->deserialized_state != t->state) {
if (t->deserialized_state == t->state)
return 0;
if (t->deserialized_state == TIMER_WAITING)
timer_enter_waiting(t, false);
else
timer_set_state(t, t->deserialized_state);
}
if (t->deserialized_state == TIMER_WAITING)
timer_enter_waiting(t, false);
else
timer_set_state(t, t->deserialized_state);
return 0;
}
@ -295,6 +298,23 @@ static void timer_enter_dead(Timer *t, TimerResult f) {
timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
}
static void timer_enter_elapsed(Timer *t, bool leave_around) {
assert(t);
/* If a unit is marked with RemainAfterElapse=yes we leave it
* around even after it elapsed once, so that starting it
* later again does not necessarily mean immediate
* retriggering. We unconditionally leave units with
* TIMER_UNIT_ACTIVE or TIMER_UNIT_INACTIVE triggers around,
* since they might be restarted automatically at any time
* later on. */
if (t->remain_after_elapse || leave_around)
timer_set_state(t, TIMER_ELAPSED);
else
timer_enter_dead(t, TIMER_SUCCESS);
}
static usec_t monotonic_to_boottime(usec_t t) {
usec_t a, b;
@ -314,6 +334,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
bool found_monotonic = false, found_realtime = false;
usec_t ts_realtime, ts_monotonic;
usec_t base = 0;
bool leave_around = false;
TimerValue *v;
int r;
@ -374,7 +395,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
break;
case TIMER_UNIT_ACTIVE:
leave_around = true;
base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
if (base <= 0)
@ -386,7 +407,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
break;
case TIMER_UNIT_INACTIVE:
leave_around = true;
base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
if (base <= 0)
@ -423,14 +444,16 @@ static void timer_enter_waiting(Timer *t, bool initial) {
if (!found_monotonic && !found_realtime) {
log_unit_debug(UNIT(t), "Timer is elapsed.");
timer_set_state(t, TIMER_ELAPSED);
timer_enter_elapsed(t, leave_around);
return;
}
if (found_monotonic) {
char buf[FORMAT_TIMESPAN_MAX];
usec_t left;
log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
left = t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0;
log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), left, 0));
if (t->monotonic_event_source) {
r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);

View File

@ -73,6 +73,7 @@ struct Timer {
bool persistent;
bool wake_system;
bool remain_after_elapse;
char *stamp_path;
};