]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
manager: switch service unit type over to using new handoff timestamping logic
authorLennart Poettering <lennart@poettering.net>
Tue, 23 Apr 2024 21:27:23 +0000 (23:27 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 25 Apr 2024 11:40:41 +0000 (13:40 +0200)
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.

NEWS
man/org.freedesktop.systemd1.xml
src/core/dbus-execute.h
src/core/execute.c
src/core/execute.h
src/core/service.c
test/units/testsuite-07.exec-timestamps.sh

diff --git a/NEWS b/NEWS
index e587ade01f1a72fe9d93afc0dead5708ed991b05..ac7f0f1154d01eb897145fe0cf58fed5d892c7ae 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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:
 
index ca8696bed5eb93692953907a3b34ccaa036597e9..9e29eda4e07868ee23a91b60c45bb79c6a041363 100644 (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>
index a1205b0997127af06b2c7411de1e315714447dda..4b7cb86d3e5070a3eeaddf848b7ac20fcf2b6134 100644 (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)
index 26a4bf1b6f502f052209e8298736c6621acad62c..7528629739bf11214cf522be61de5dcf418382f3 100644 (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,
index 202ef5f82b9cd55e1f635d13475b312a04d4df18..6a313640de2d3628affe42c70f2dc14e03980239 100644 (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);
 
index 4a512fd24b207a836eddcbf0b7b52351788d35fb..b3fe2c0b1f8f87a40458c8abb2c116a8b5f14977 100644 (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,
index 799bc89e06ef5b2f3c33a5812fca337e711c6d8a..0211166ae3c3883b7e581b47546779353be30502 100755 (executable)
@@ -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 ]]