core: add RemainAfterElapse= setting to timer units
authorLennart Poettering <lennart@poettering.net>
Tue, 17 Nov 2015 19:13:36 +0000 (20:13 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 17 Nov 2015 19:48:23 +0000 (20:48 +0100)
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.

man/systemd.timer.xml
src/core/dbus-timer.c
src/core/load-fragment-gperf.gperf.m4
src/core/timer.c
src/core/timer.h

index 8cf6c46..3841588 100644 (file)
         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>
 
index a8a280d..2e6c479 100644 (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;
index 7994180..74ef72d 100644 (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
index 51b1d87..0587452 100644 (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);
index ac5af6a..6bc9fbe 100644 (file)
@@ -73,6 +73,7 @@ struct Timer {
 
         bool persistent;
         bool wake_system;
+        bool remain_after_elapse;
 
         char *stamp_path;
 };