1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-23 02:04:32 +03:00

manager: switch service unit type over to using new handoff timestamping logic

Also: rename Handover → Handoff. I think it makes it clearer that this
is not really about handing over any resources, but that the executor is
out off the game from that point on.
This commit is contained in:
Lennart Poettering 2024-04-23 23:27:23 +02:00
parent 12001b1bf0
commit 3c1d1ca146
7 changed files with 74 additions and 37 deletions

13
NEWS
View File

@ -198,13 +198,12 @@ CHANGES WITH 256-rc1:
PID 1 will start to have the effect of shutting down the system
cleanly).
* New D-Bus properties ExecMainHandoverTimestamp and
ExecMainHandoverTimestampMonotonic are now published by services of
type exec, dbus, notify, and notify-reload.
This timestamp is taken as the very last operation before executing
a service's binary, which allows users to accurately track when
execution control of the process is handed over from systemd to the
payload.
* New D-Bus properties ExecMainHandoffTimestamp and
ExecMainHandoffTimestampMonotonic are now published by services
units. This timestamp is taken as the very last operation before
handing off control to invoked binaries. This information is
available for other unit types that fork off processes (i.e. mount,
swap, socket units), but currently only via "systemd-analyze dump".
Journal:

View File

@ -2766,8 +2766,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
readonly t ExecMainStartTimestampMonotonic = ...;
readonly t ExecMainExitTimestamp = ...;
readonly t ExecMainExitTimestampMonotonic = ...;
readonly t ExecMainHandoverTimestamp = ...;
readonly t ExecMainHandoverTimestampMonotonic = ...;
readonly t ExecMainHandoffTimestamp = ...;
readonly t ExecMainHandoffTimestampMonotonic = ...;
readonly u ExecMainPID = ...;
readonly i ExecMainCode = ...;
readonly i ExecMainStatus = ...;
@ -4057,9 +4057,9 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainExitTimestampMonotonic"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainHandoverTimestamp"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainHandoffTimestamp"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainHandoverTimestampMonotonic"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainHandoffTimestampMonotonic"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExecMainPID"/>
@ -4710,18 +4710,20 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<para><varname>ExecMainStartTimestamp</varname>, <varname>ExecMainStartTimestampMonotonic</varname>,
<varname>ExecMainExitTimestamp</varname>, <varname>ExecMainExitTimestampMonotonic</varname>,
<varname>ExecMainHandoverTimestamp</varname>, <varname>ExecMainHandoverTimestampMonotonic</varname>,
<varname>ExecMainHandoffTimestamp</varname>, <varname>ExecMainHandoffTimestampMonotonic</varname>,
<varname>ExecMainPID</varname>, <varname>ExecMainCode</varname>, <varname>ExecMainStatus</varname>
contain information about the main process of the service as far as it is known. The
<varname>ExecMainStartTimestamp</varname> timestamps record when the main child process is spawned by
the service manager. <varname>ExecMainExitTimestamp</varname> timestamps record when the main child
process exit has been detected by the service manager. <varname>ExecMainHandoverTimestamp</varname>
timestamps record when the service executable is executed by <command>systemd-executor</command> for
services of type <literal>exec</literal>, <literal>dbus</literal>, <literal>notify</literal>, and
<literal>notify-reload</literal>. This is often the same runtime information that is stored in
<varname>ExecStart=</varname>. However, it deviates for <varname>Type=forking</varname> services where
the main process of the service is not forked off systemd directly. These fields either contain
information of the last run of the process or of the current running process.</para>
<varname>ExecMainStartTimestamp</varname> timestamps record when the main process of the service is
created. <varname>ExecMainExitTimestamp</varname> timestamps record when the main process exit has been
detected by the service manager. <varname>ExecMainHandoffTimestamp</varname> timestamps records when
the service binary is about to be executed by <command>systemd-executor</command> (this timestamp is
recorded regardless if the immediately following <function>execve()</function> system call succeeds or
fails). This is often the same runtime information that is also maintained for
<varname>ExecStart=</varname>. However, it deviates for services with <varname>Type=forking</varname>
as well as services that use <varname>MAINPID=</varname> <function>sd_notify()</function> messages as
the main process of the service is not forked off by the service manager directly in that case. These
fields either contain information of the last run of the process or of the current running
process.</para>
<para><varname>MainPID</varname> and <varname>ControlPID</varname> contain the main and control PID of
the service. The main PID is the current main PID of the service and is 0 when the service currently
@ -12067,8 +12069,8 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<varname>EffectiveMemoryMax</varname>,
<varname>EffectiveTasksMax</varname>,
<varname>MemoryZSwapWriteback</varname>,
<varname>ExecMainHandoverTimestampMonotonic</varname>, and
<varname>ExecMainHandoverTimestamp</varname> were added in version 256.</para>
<varname>ExecMainHandoffTimestampMonotonic</varname>, and
<varname>ExecMainHandoffTimestamp</varname> were added in version 256.</para>
</refsect2>
<refsect2>
<title>Socket Unit Objects</title>

View File

@ -9,7 +9,7 @@
#define BUS_EXEC_STATUS_VTABLE(prefix, offset, flags) \
BUS_PROPERTY_DUAL_TIMESTAMP(prefix "StartTimestamp", (offset) + offsetof(ExecStatus, start_timestamp), flags), \
BUS_PROPERTY_DUAL_TIMESTAMP(prefix "ExitTimestamp", (offset) + offsetof(ExecStatus, exit_timestamp), flags), \
BUS_PROPERTY_DUAL_TIMESTAMP(prefix "HandoverTimestamp", (offset) + offsetof(ExecStatus, handover_timestamp), flags), \
BUS_PROPERTY_DUAL_TIMESTAMP(prefix "HandoffTimestamp", (offset) + offsetof(ExecStatus, handoff_timestamp), flags), \
SD_BUS_PROPERTY(prefix "PID", "u", bus_property_get_pid, (offset) + offsetof(ExecStatus, pid), flags), \
SD_BUS_PROPERTY(prefix "Code", "i", bus_property_get_int, (offset) + offsetof(ExecStatus, code), flags), \
SD_BUS_PROPERTY(prefix "Status", "i", bus_property_get_int, (offset) + offsetof(ExecStatus, status), flags)

View File

@ -1842,6 +1842,19 @@ void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int
(void) utmp_put_dead_process(context->utmp_id, pid, code, status);
}
void exec_status_handoff(ExecStatus *s, const struct ucred *ucred, const dual_timestamp *ts) {
assert(s);
assert(ucred);
assert(ts);
if (ucred->pid != s->pid)
*s = (ExecStatus) {
.pid = ucred->pid,
};
s->handoff_timestamp = *ts;
}
void exec_status_reset(ExecStatus *s) {
assert(s);
@ -1866,10 +1879,10 @@ void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix) {
"%sStart Timestamp: %s\n",
prefix, FORMAT_TIMESTAMP(s->start_timestamp.realtime));
if (dual_timestamp_is_set(&s->handover_timestamp))
if (dual_timestamp_is_set(&s->handoff_timestamp))
fprintf(f,
"%sHandover Timestamp: %s\n",
prefix, FORMAT_TIMESTAMP(s->handover_timestamp.realtime));
"%sHandoff Timestamp: %s\n",
prefix, FORMAT_TIMESTAMP(s->handoff_timestamp.realtime));
if (dual_timestamp_is_set(&s->exit_timestamp))
fprintf(f,

View File

@ -91,7 +91,7 @@ typedef enum ExecKeyringMode {
struct ExecStatus {
dual_timestamp start_timestamp;
dual_timestamp exit_timestamp;
dual_timestamp handover_timestamp;
dual_timestamp handoff_timestamp;
pid_t pid;
int code; /* as in siginfo_t::si_code */
int status; /* as in siginfo_t::si_status */
@ -444,9 +444,7 @@ struct ExecParameters {
int stdout_fd;
int stderr_fd;
/* An fd that is closed by the execve(), and thus will result in EOF when the execve() is done. It
* will also be used to send a timestamp taken as the very last operation before execve, for
* tracking purposes. */
/* An fd that is closed by the execve(), and thus will result in EOF when the execve() is done. */
int exec_fd;
char *notify_socket;
@ -547,6 +545,7 @@ char** exec_context_get_restrict_filesystems(const ExecContext *c);
void exec_status_start(ExecStatus *s, pid_t pid);
void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status);
void exec_status_handoff(ExecStatus *s, const struct ucred *ucred, const dual_timestamp *ts);
void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix);
void exec_status_reset(ExecStatus *s);

View File

@ -3009,7 +3009,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
(void) serialize_item_format(f, "main-exec-status-pid", PID_FMT, s->main_exec_status.pid);
(void) serialize_dual_timestamp(f, "main-exec-status-start", &s->main_exec_status.start_timestamp);
(void) serialize_dual_timestamp(f, "main-exec-status-exit", &s->main_exec_status.exit_timestamp);
(void) serialize_dual_timestamp(f, "main-exec-status-handover", &s->main_exec_status.handover_timestamp);
(void) serialize_dual_timestamp(f, "main-exec-status-handoff", &s->main_exec_status.handoff_timestamp);
if (dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) {
(void) serialize_item_format(f, "main-exec-status-code", "%i", s->main_exec_status.code);
@ -3294,8 +3294,8 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
deserialize_dual_timestamp(value, &s->main_exec_status.start_timestamp);
else if (streq(key, "main-exec-status-exit"))
deserialize_dual_timestamp(value, &s->main_exec_status.exit_timestamp);
else if (streq(key, "main-exec-status-handover"))
deserialize_dual_timestamp(value, &s->main_exec_status.handover_timestamp);
else if (streq(key, "main-exec-status-handoff"))
deserialize_dual_timestamp(value, &s->main_exec_status.handoff_timestamp);
else if (streq(key, "notify-access-override")) {
NotifyAccess notify_access;
@ -4578,6 +4578,29 @@ static void service_notify_message(
unit_add_to_dbus_queue(u);
}
static void service_handoff_timestamp(
Unit *u,
const struct ucred *ucred,
const dual_timestamp *ts) {
Service *s = ASSERT_PTR(SERVICE(u));
assert(ucred);
assert(ts);
if (s->main_pid.pid == ucred->pid) {
if (s->main_command)
exec_status_handoff(&s->main_command->exec_status, ucred, ts);
exec_status_handoff(&s->main_exec_status, ucred, ts);
} else if (s->control_pid.pid == ucred->pid && s->control_command)
exec_status_handoff(&s->control_command->exec_status, ucred, ts);
else
return;
unit_add_to_dbus_queue(u);
}
static int service_get_timeout(Unit *u, usec_t *timeout) {
Service *s = ASSERT_PTR(SERVICE(u));
uint64_t t;
@ -5163,6 +5186,7 @@ const UnitVTable service_vtable = {
.notify_cgroup_empty = service_notify_cgroup_empty_event,
.notify_cgroup_oom = service_notify_cgroup_oom_event,
.notify_message = service_notify_message,
.notify_handoff_timestamp = service_handoff_timestamp,
.main_pid = service_main_pid,
.control_pid = service_control_pid,

View File

@ -8,10 +8,10 @@ set -o pipefail
systemd-run --service-type notify --property NotifyAccess=all --unit notify.service --wait sh -c 'systemd-notify --ready; exit 1' || :
start=$(systemctl show --property=ExecMainStartTimestampMonotonic --value notify.service)
handover=$(systemctl show --property=ExecMainHandoverTimestampMonotonic --value notify.service)
handoff=$(systemctl show --property=ExecMainHandoffTimestampMonotonic --value notify.service)
active=$(systemctl show --property=ActiveEnterTimestampMonotonic --value notify.service)
exit=$(systemctl show --property=ExecMainExitTimestampMonotonic --value notify.service)
[[ $start -le $handover ]]
[[ $handover -le $active ]]
[[ $start -le $handoff ]]
[[ $handoff -le $active ]]
[[ $active -le $exit ]]