/* If DeferReactivation= is enabled, schedule the job based on the last time
* the trigger unit entered inactivity. Otherwise, if we know the last time
* this was triggered, schedule the job based relative to that. If we don't,
- * just start from the activation time or realtime.
- *
- * Unless we have a real last-trigger time, we subtract the random_offset because
- * any event that elapsed within the last random_offset has actually been delayed
- * and thus hasn't truly elapsed yet. */
-
+ * just start from the activation time or realtime. */
if (t->defer_reactivation &&
dual_timestamp_is_set(&trigger->inactive_enter_timestamp)) {
if (dual_timestamp_is_set(&t->last_trigger))
if (t->last_trigger.monotonic < boot_monotonic)
rebase_after_boot_time = true;
} else if (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp))
- b = UNIT(t)->inactive_exit_timestamp.realtime - random_offset;
+ b = UNIT(t)->inactive_exit_timestamp.realtime;
else {
- b = ts.realtime - random_offset;
+ b = ts.realtime;
rebase_after_boot_time = true;
}
* base to calendar_spec_next_usec() would schedule the next elapse relative to
* that stale time instead of now, so systemctl list-timers keeps showing the
* pre-adjustment elapse and the timer never catches up (see #6036). Clamp to
- * now (minus the random offset, matching the "start from now" branch above) so
- * we recalculate from the current time. */
+ * now so we recalculate from the current time. */
log_unit_debug(UNIT(t),
"Calendar timer base time %s is in the future, recalculating from the current time.",
FORMAT_TIMESTAMP(b));
- b = ts.realtime - random_offset;
+ b = ts.realtime;
}
+ /* We always subtract random_offset from the base time because
+ * calendar_spec_next_usec() finds the next calendar event, and then we add the
+ * offset back afterwards (see below). The base time needs to be in "pre-offset"
+ * space so the next calendar match is computed correctly. Without this, a timer
+ * that fires late (e.g. persistent catch-up) would skip the next scheduled
+ * activation. */
+ b = usec_sub_unsigned(b, random_offset);
+
r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
if (r < 0)
continue;