chiark / gitweb /
service: introduce Type=idle and use it for gettys
authorLennart Poettering <lennart@poettering.net>
Tue, 24 Apr 2012 12:28:00 +0000 (14:28 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 24 Apr 2012 12:42:24 +0000 (14:42 +0200)
Type=idle is much like Type=simple, however between the fork() and the
exec() in the child we wait until PID 1 informs us that no jobs are
left.

This is mostly a cosmetic fix to make gettys appear only after all boot
output is finished and complete.

Note that this does not impact the normal job logic as we do not delay
the completion of any jobs. We just delay the invocation of the actual
binary, and only for services that otherwise would be of Type=simple.

16 files changed:
src/core/execute.c
src/core/execute.h
src/core/manager.c
src/core/manager.h
src/core/mount.c
src/core/service.c
src/core/service.h
src/core/socket.c
src/core/swap.c
src/core/transaction.c
units/console-getty.service.m4.in
units/console-shell.service.m4.in
units/emergency.service.in
units/getty@.service.m4
units/rescue.service.m4.in
units/serial-getty@.service.m4

index c59f7e2daa63b3c50bfc8ecb081a2e9be9fb62ba..99a7881f1cbbc81c03d2af9fe36ca5dfe87e7ec1 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/mount.h>
 #include <linux/fs.h>
 #include <linux/oom.h>
+#include <sys/poll.h>
 
 #ifdef HAVE_PAM
 #include <security/pam_appl.h>
@@ -963,6 +964,7 @@ int exec_spawn(ExecCommand *command,
                CGroupBonding *cgroup_bondings,
                CGroupAttribute *cgroup_attributes,
                const char *cgroup_suffix,
+               int idle_pipe[2],
                pid_t *ret) {
 
         pid_t pid;
@@ -1050,6 +1052,15 @@ int exec_spawn(ExecCommand *command,
                         goto fail_child;
                 }
 
+                if (idle_pipe) {
+                        if (idle_pipe[1] >= 0)
+                                close_nointr_nofail(idle_pipe[1]);
+                        if (idle_pipe[0] >= 0) {
+                                fd_wait_for_event(idle_pipe[0], POLLHUP, DEFAULT_TIMEOUT_USEC);
+                                close_nointr_nofail(idle_pipe[0]);
+                        }
+                }
+
                 /* Close sockets very early to make sure we don't
                  * block init reexecution because it cannot bind its
                  * sockets */
index 428bb7c9bfe0530ef39190f14351d5715841e109..03c63d465a10950636264b060f9502635d11e0c3 100644 (file)
@@ -193,6 +193,7 @@ int exec_spawn(ExecCommand *command,
                struct CGroupBonding *cgroup_bondings,
                struct CGroupAttribute *cgroup_attributes,
                const char *cgroup_suffix,
+               int pipe_fd[2],
                pid_t *ret);
 
 void exec_command_done(ExecCommand *c);
index f7ccba6235d87752817073d981fe6251d7c8af49..a6013668b8a8221997cf92cda3f3430e506f4758 100644 (file)
@@ -259,6 +259,7 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
         m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1;
         m->exit_code = _MANAGER_EXIT_CODE_INVALID;
         m->pin_cgroupfs_fd = -1;
+        m->idle_pipe[0] = m->idle_pipe[1] = -1;
 
 #ifdef HAVE_AUDIT
         m->audit_fd = -1;
@@ -518,6 +519,8 @@ void manager_free(Manager *m) {
         hashmap_free(m->cgroup_bondings);
         set_free_free(m->unit_path_cache);
 
+        close_pipe(m->idle_pipe);
+
         free(m);
 }
 
@@ -1962,10 +1965,13 @@ void manager_check_finished(Manager *m) {
 
         assert(m);
 
-        if (dual_timestamp_is_set(&m->finish_timestamp))
+        if (hashmap_size(m->jobs) > 0)
                 return;
 
-        if (hashmap_size(m->jobs) > 0)
+        /* Notify Type=idle units that we are done now */
+        close_pipe(m->idle_pipe);
+
+        if (dual_timestamp_is_set(&m->finish_timestamp))
                 return;
 
         dual_timestamp_get(&m->finish_timestamp);
index 808a0d4286c6b95f40fe1945df0164f0257b1623..154c1faeb7289797f810ce4cd1c53a62f4205591 100644 (file)
@@ -227,6 +227,9 @@ struct Manager {
 
         unsigned n_installed_jobs;
         unsigned n_failed_jobs;
+
+        /* Type=idle pipes */
+        int idle_pipe[2];
 };
 
 int manager_new(ManagerRunningAs running_as, Manager **m);
index e662af0c87855516ac7a0f3b9f191b93ee847eea..3357b7df5b26a3662287db3da2f1327fecd12e88 100644 (file)
@@ -801,6 +801,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
                             UNIT(m)->cgroup_bondings,
                             UNIT(m)->cgroup_attributes,
                             NULL,
+                            NULL,
                             &pid)) < 0)
                 goto fail;
 
index 59dd71294bcafef36df4a9c3f25e2708da7b0328..4358a948de92c3fe409f232cddde0c55a42b8539 100644 (file)
@@ -1769,6 +1769,7 @@ static int service_spawn(
                        UNIT(s)->cgroup_bondings,
                        UNIT(s)->cgroup_attributes,
                        is_control ? "control" : NULL,
+                       s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL,
                        &pid);
 
         if (r < 0)
@@ -2130,7 +2131,7 @@ static void service_enter_start(Service *s) {
         if (r < 0)
                 goto fail;
 
-        if (s->type == SERVICE_SIMPLE) {
+        if (s->type == SERVICE_SIMPLE || s->type == SERVICE_IDLE) {
                 /* For simple services we immediately start
                  * the START_POST binaries. */
 
@@ -3714,7 +3715,8 @@ static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
         [SERVICE_FORKING] = "forking",
         [SERVICE_ONESHOT] = "oneshot",
         [SERVICE_DBUS] = "dbus",
-        [SERVICE_NOTIFY] = "notify"
+        [SERVICE_NOTIFY] = "notify",
+        [SERVICE_IDLE] = "idle"
 };
 
 DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
index eb41314931021dc5bb680cea94bd3d4e7b681e45..819672f61770b9578413c5653de483e1296fd66f 100644 (file)
@@ -65,6 +65,7 @@ typedef enum ServiceType {
         SERVICE_ONESHOT,  /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
         SERVICE_DBUS,     /* we fork and wait until a specific D-Bus name appears on the bus */
         SERVICE_NOTIFY,   /* we fork and wait until a daemon sends us a ready message with sd_notify() */
+        SERVICE_IDLE,     /* much like simple, but delay exec() until all jobs are dispatched. */
         _SERVICE_TYPE_MAX,
         _SERVICE_TYPE_INVALID = -1
 } ServiceType;
index 31aff5bcec7b40d9c7942437da414015fd33b1c0..1d56829baff629602d2458b1771a8af761fa9faa 100644 (file)
@@ -1152,6 +1152,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
                        UNIT(s)->cgroup_bondings,
                        UNIT(s)->cgroup_attributes,
                        NULL,
+                       NULL,
                        &pid);
 
         strv_free(argv);
index 9c30c11bb468eebb336250d58005741e1e41bfac..fea3f6887a882977b5fba6c58cfcd4fb3c7227e8 100644 (file)
@@ -620,6 +620,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
                             UNIT(s)->cgroup_bondings,
                             UNIT(s)->cgroup_attributes,
                             NULL,
+                            NULL,
                             &pid)) < 0)
                 goto fail;
 
index aee155f5196070254d3aabee858c057ea8aeba56..09ed80737d4885c945edde7f042e68eea1fd7618 100644 (file)
@@ -19,6 +19,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <unistd.h>
+#include <fcntl.h>
+
 #include "transaction.h"
 #include "bus-errors.h"
 
@@ -693,6 +696,17 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e
 
         assert(hashmap_isempty(tr->jobs));
 
+        if (!hashmap_isempty(m->jobs)) {
+                /* Are there any jobs now? Then make sure we have the
+                 * idle pipe around. We don't really care too much
+                 * whether this works or not, as the idle pipe is a
+                 * feature for cosmetics, not actually useful for
+                 * anything beyond that. */
+
+                if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0)
+                        pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
+        }
+
         return 0;
 }
 
index 9473d61dfe122763e220933098309f96524a4a92..298082b3a93917de4031e57e6378d2e3f6858475 100644 (file)
@@ -30,6 +30,7 @@ Before=getty.target
 
 [Service]
 ExecStart=-/sbin/agetty --noclear -s console 115200,38400,9600
+Type=idle
 Restart=always
 RestartSec=0
 UtmpIdentifier=cons
index 7d0da9b8608a67447ab31525eba651c6e7b81c81..4f795e16ac0e44103bc5579aa536a3c332624ecc 100644 (file)
@@ -33,6 +33,7 @@ Environment=HOME=/root
 WorkingDirectory=/root
 ExecStart=-/sbin/sulogin
 ExecStopPost=-@SYSTEMCTL@ poweroff
+Type=idle
 StandardInput=tty-force
 StandardOutput=inherit
 StandardError=inherit
index c1421ba22c64c56a83636e25ca18980e6dc9091b..75007563d736cdc67d09629d182d636c9b4e2ddc 100644 (file)
@@ -20,6 +20,7 @@ ExecStartPre=-/bin/plymouth quit
 ExecStartPre=-/bin/echo 'Welcome to emergency mode. Use "systemctl default" or ^D to enter default mode.'
 ExecStart=-/sbin/sulogin
 ExecStopPost=@SYSTEMCTL@ --fail --no-block default
+Type=idle
 StandardInput=tty-force
 StandardOutput=inherit
 StandardError=inherit
index 17c76f5b3154e6065b24ab493a7cab6cf1e9dddb..431a3dd722c6def4834d44e99f71065cfc1b683b 100644 (file)
@@ -41,6 +41,7 @@ ConditionPathExists=/dev/tty0
 [Service]
 Environment=TERM=linux
 ExecStart=-/sbin/agetty %I 38400
+Type=idle
 Restart=always
 RestartSec=0
 UtmpIdentifier=%I
index c736f83478c627d3bddcefd9ac4ac9061e6961dc..3adfcf45bd5c71f2a7aadaee78139a9a7ac9f13d 100644 (file)
@@ -33,6 +33,7 @@ m4_ifdef(`TARGET_MEEGO',
 ExecStart=-/bin/bash -c "exec ${SINGLE}"',
 `ExecStart=-/sbin/sulogin'))))
 ExecStopPost=-@SYSTEMCTL@ --fail --no-block default
+Type=idle
 StandardInput=tty-force
 StandardOutput=inherit
 StandardError=inherit
index 93bc643e6b6a407f0583506287c386a6580e61f0..366b2d0710d05256f8db01630d8b62d67c16f570 100644 (file)
@@ -37,6 +37,7 @@ IgnoreOnIsolate=yes
 [Service]
 Environment=TERM=vt102
 ExecStart=-/sbin/agetty -s %I 115200,38400,9600
+Type=idle
 Restart=always
 RestartSec=0
 UtmpIdentifier=%I