]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: always calculate the next restart interval
authorMike Yuan <me@yhndnzj.com>
Wed, 29 Mar 2023 20:04:22 +0000 (04:04 +0800)
committerLuca Boccassi <luca.boccassi@gmail.com>
Fri, 31 Mar 2023 00:22:58 +0000 (01:22 +0100)
Follow-up for #26902 and #26971

Let's always calculate the next restart interval
since that's more useful.

For that, we add 1 to s->n_restarts unconditionally,
and change RestartUSecCurrent property to RestartUSecNext.

man/org.freedesktop.systemd1.xml
src/core/dbus-service.c
src/core/service.c
src/core/service.h

index 1a82a19bbdc589f8399e0805502cb38a130e0192..50680e6b37af8b8a8324084e087c44bfc001295c 100644 (file)
@@ -2578,7 +2578,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly t RestartUSecMax = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
-      readonly t RestartUSecCurrent = ...;
+      readonly t RestartUSecNext = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly t TimeoutStartUSec = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
@@ -3208,7 +3208,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--property RestartUSecMax is not documented!-->
 
-    <!--property RestartUSecCurrent is not documented!-->
+    <!--property RestartUSecNext is not documented!-->
 
     <!--property TimeoutStartFailureMode is not documented!-->
 
@@ -3774,7 +3774,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="RestartUSecMax"/>
 
-    <variablelist class="dbus-property" generated="True" extra-ref="RestartUSecCurrent"/>
+    <variablelist class="dbus-property" generated="True" extra-ref="RestartUSecNext"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="TimeoutStartUSec"/>
 
index 742893370f68c10347742932e737f4658f56c256..a6758e616b1504d5bec5e4cdc1517770abfb4f2c 100644 (file)
@@ -35,7 +35,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, Service
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart);
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
 static BUS_DEFINE_PROPERTY_GET2(property_get_notify_access, "s", Service, service_get_notify_access, notify_access_to_string);
-static BUS_DEFINE_PROPERTY_GET(property_get_restart_usec_current, "t", Service, service_restart_usec);
+static BUS_DEFINE_PROPERTY_GET(property_get_restart_usec_next, "t", Service, service_restart_usec_next);
 static BUS_DEFINE_PROPERTY_GET(property_get_timeout_abort_usec, "t", Service, service_timeout_abort_usec);
 static BUS_DEFINE_PROPERTY_GET(property_get_watchdog_usec, "t", Service, service_get_watchdog_usec);
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_timeout_failure_mode, service_timeout_failure_mode, ServiceTimeoutFailureMode);
@@ -296,7 +296,7 @@ const sd_bus_vtable bus_service_vtable[] = {
         SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RestartSteps", "u", bus_property_get_unsigned, offsetof(Service, restart_steps), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RestartUSecMax", "t", bus_property_get_usec, offsetof(Service, restart_usec_max), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("RestartUSecCurrent", "t", property_get_restart_usec_current, 0, 0),
+        SD_BUS_PROPERTY("RestartUSecNext", "t", property_get_restart_usec_next, 0, 0),
         SD_BUS_PROPERTY("TimeoutStartUSec", "t", bus_property_get_usec, offsetof(Service, timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Service, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("TimeoutAbortUSec", "t", property_get_timeout_abort_usec, 0, 0),
index c4a7be890d65da986a26b76cb7d46b4eb9156791..e0e56af19c7b285c2ccce20b98788a784d91bd1b 100644 (file)
@@ -268,38 +268,37 @@ static void service_start_watchdog(Service *s) {
                 log_unit_warning_errno(UNIT(s), r, "Failed to install watchdog timer: %m");
 }
 
-usec_t service_restart_usec(Service *s) {
-        unsigned n_restarts;
-        long double unit;
+usec_t service_restart_usec_next(Service *s) {
+        unsigned n_restarts_next;
         usec_t value;
 
         assert(s);
 
-        /* s->n_restarts is not yet updated when we're in these states, so let's add 1 to it manually.
-         * Note that for SERVICE_AUTO_RESTART a restart job might have been enqueued,
-         * i.e. s->n_restarts is already increased. But we assume it's not since the time
-         * between job enqueuing and running is usually neglectable compared to the time
-         * we'll be sleeping. */
-        n_restarts = s->n_restarts +
-                     (IN_SET(s->state, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART) ? 1 : 0);
+        /* When the service state is in SERVICE_*_BEFORE_AUTO_RESTART or SERVICE_AUTO_RESTART,
+         * we still need to add 1 to s->n_restarts manually because s->n_restarts is not updated
+         * until a restart job is enqueued. Note that for SERVICE_AUTO_RESTART, that might have been
+         * the case, i.e. s->n_restarts is already increased. But we assume it's not since the time
+         * between job enqueuing and running is usually neglectable compared to the time we'll be sleeping. */
+        n_restarts_next = s->n_restarts + 1;
 
-        /* n_restarts can equal to 0 if no restart has happened nor planned */
-        if (n_restarts <= 1 ||
+        if (n_restarts_next <= 1 ||
             s->restart_steps == 0 ||
             s->restart_usec_max == USEC_INFINITY ||
             s->restart_usec >= s->restart_usec_max)
                 value = s->restart_usec;
-        else if (n_restarts > s->restart_steps)
+        else if (n_restarts_next > s->restart_steps)
                 value = s->restart_usec_max;
         else {
                 /* Enforced in service_verify() and above */
                 assert(s->restart_usec_max > s->restart_usec);
 
-                unit = powl(s->restart_usec_max - s->restart_usec, 1.0L / s->restart_steps);
-                value = usec_add(s->restart_usec, (usec_t) powl(unit, n_restarts - 1));
+                /* ((restart_usec_max - restart_usec)^(1/restart_steps))^(n_restart_next - 1) */
+                value = usec_add(s->restart_usec,
+                                 (usec_t) powl(s->restart_usec_max - s->restart_usec,
+                                               (long double) (n_restarts_next - 1) / s->restart_steps));
         }
 
-        log_unit_debug(UNIT(s), "Restart interval calculated as: %s", FORMAT_TIMESPAN(value, 0));
+        log_unit_debug(UNIT(s), "Next restart interval calculated as: %s", FORMAT_TIMESPAN(value, 0));
         return value;
 }
 
@@ -1270,7 +1269,7 @@ static usec_t service_coldplug_timeout(Service *s) {
                 return usec_add(UNIT(s)->state_change_timestamp.monotonic, service_timeout_abort_usec(s));
 
         case SERVICE_AUTO_RESTART:
-                return usec_add(UNIT(s)->inactive_enter_timestamp.monotonic, service_restart_usec(s));
+                return usec_add(UNIT(s)->inactive_enter_timestamp.monotonic, service_restart_usec_next(s));
 
         case SERVICE_CLEANING:
                 return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->exec_context.timeout_clean_usec);
@@ -1963,7 +1962,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
                  * state from this transitionary UNIT_INACTIVE state by looking at the low-level states. */
                 service_set_state(s, restart_state);
 
-                r = service_arm_timer(s, /* relative= */ true, service_restart_usec(s));
+                r = service_arm_timer(s, /* relative= */ true, service_restart_usec_next(s));
                 if (r < 0)
                         goto fail;
 
@@ -4200,7 +4199,7 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
                 if (s->restart_usec > 0)
                         log_unit_debug(UNIT(s),
                                        "Service restart interval %s expired, scheduling restart.",
-                                       FORMAT_TIMESPAN(service_restart_usec(s), USEC_PER_SEC));
+                                       FORMAT_TIMESPAN(service_restart_usec_next(s), USEC_PER_SEC));
                 else
                         log_unit_debug(UNIT(s),
                                        "Service has no hold-off time (RestartSec=0), scheduling restart.");
index 156d32ca17143c44abf4e5ebf711a079b91a7ac4..03edb18e31e5c99d340c213045f7702fabf50e2a 100644 (file)
@@ -245,7 +245,7 @@ extern const UnitVTable service_vtable;
 int service_set_socket_fd(Service *s, int fd, struct Socket *socket, struct SocketPeer *peer, bool selinux_context_net);
 void service_close_socket_fd(Service *s);
 
-usec_t service_restart_usec(Service *s);
+usec_t service_restart_usec_next(Service *s);
 
 const char* service_restart_to_string(ServiceRestart i) _const_;
 ServiceRestart service_restart_from_string(const char *s) _pure_;