mirror of
https://github.com/morgan9e/systemd
synced 2026-04-15 08:56:15 +09:00
By default, in instances where timers are running on a realtime schedule, if a service takes longer to run than the interval of a timer, the service will immediately start again when the previous invocation finishes. This is caused by the fact that the next elapse is calculated based on the last trigger time, which, combined with the fact that the interval is shorter than the runtime of the service, causes that elapse to be in the past, which in turn means the timer will trigger as soon as the service finishes running. This behavior can be changed by enabling the new DeferReactivation setting, which will cause the next calendar elapse to be calculated based on when the trigger unit enters inactivity, rather than the last trigger time. Thus, if a timer is on an realtime interval, the trigger will always adhere to that specified interval. E.g. if you have a timer that runs on a minutely interval, the setting guarantees that triggers will happen at *:*:00 times, whereas by default this may skew depending on how long the service runs. Co-authored-by: Matteo Croce <teknoraver@meta.com>
93 lines
2.4 KiB
C
93 lines
2.4 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
#pragma once
|
|
|
|
typedef struct Timer Timer;
|
|
typedef struct ActivationDetailsTimer ActivationDetailsTimer;
|
|
|
|
#include "calendarspec.h"
|
|
#include "unit.h"
|
|
|
|
typedef enum TimerBase {
|
|
TIMER_ACTIVE,
|
|
TIMER_BOOT,
|
|
TIMER_STARTUP,
|
|
TIMER_UNIT_ACTIVE,
|
|
TIMER_UNIT_INACTIVE,
|
|
TIMER_CALENDAR,
|
|
_TIMER_BASE_MAX,
|
|
_TIMER_BASE_INVALID = -EINVAL,
|
|
} TimerBase;
|
|
|
|
typedef struct TimerValue {
|
|
TimerBase base;
|
|
bool disabled;
|
|
|
|
usec_t value; /* only for monotonic events */
|
|
CalendarSpec *calendar_spec; /* only for calendar events */
|
|
usec_t next_elapse;
|
|
|
|
LIST_FIELDS(struct TimerValue, value);
|
|
} TimerValue;
|
|
|
|
typedef enum TimerResult {
|
|
TIMER_SUCCESS,
|
|
TIMER_FAILURE_RESOURCES,
|
|
TIMER_FAILURE_START_LIMIT_HIT,
|
|
_TIMER_RESULT_MAX,
|
|
_TIMER_RESULT_INVALID = -EINVAL,
|
|
} TimerResult;
|
|
|
|
struct Timer {
|
|
Unit meta;
|
|
|
|
usec_t accuracy_usec;
|
|
usec_t random_usec;
|
|
|
|
LIST_HEAD(TimerValue, values);
|
|
usec_t next_elapse_realtime;
|
|
usec_t next_elapse_monotonic_or_boottime;
|
|
dual_timestamp last_trigger;
|
|
|
|
TimerState state, deserialized_state;
|
|
|
|
sd_event_source *monotonic_event_source;
|
|
sd_event_source *realtime_event_source;
|
|
|
|
TimerResult result;
|
|
|
|
bool persistent;
|
|
bool wake_system;
|
|
bool remain_after_elapse;
|
|
bool on_clock_change;
|
|
bool on_timezone_change;
|
|
bool fixed_random_delay;
|
|
bool defer_reactivation;
|
|
|
|
char *stamp_path;
|
|
};
|
|
|
|
struct ActivationDetailsTimer {
|
|
ActivationDetails meta;
|
|
dual_timestamp last_trigger;
|
|
};
|
|
|
|
#define TIMER_MONOTONIC_CLOCK(t) ((t)->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC)
|
|
|
|
uint64_t timer_next_elapse_monotonic(const Timer *t);
|
|
|
|
void timer_free_values(Timer *t);
|
|
|
|
extern const UnitVTable timer_vtable;
|
|
extern const ActivationDetailsVTable activation_details_timer_vtable;
|
|
|
|
const char* timer_base_to_string(TimerBase i) _const_;
|
|
TimerBase timer_base_from_string(const char *s) _pure_;
|
|
|
|
char* timer_base_to_usec_string(TimerBase i);
|
|
|
|
const char* timer_result_to_string(TimerResult i) _const_;
|
|
TimerResult timer_result_from_string(const char *s) _pure_;
|
|
|
|
DEFINE_CAST(TIMER, Timer);
|
|
DEFINE_ACTIVATION_DETAILS_CAST(ACTIVATION_DETAILS_TIMER, ActivationDetailsTimer, TIMER);
|