mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
service: introduce Type=idle and use it for gettys
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.
This commit is contained in:
parent
8d8e945624
commit
f2b6878955
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -33,6 +33,7 @@ Environment=HOME=/root
|
||||
WorkingDirectory=/root
|
||||
ExecStart=-/sbin/sulogin
|
||||
ExecStopPost=-@SYSTEMCTL@ poweroff
|
||||
Type=idle
|
||||
StandardInput=tty-force
|
||||
StandardOutput=inherit
|
||||
StandardError=inherit
|
||||
|
@ -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
|
||||
|
@ -41,6 +41,7 @@ ConditionPathExists=/dev/tty0
|
||||
[Service]
|
||||
Environment=TERM=linux
|
||||
ExecStart=-/sbin/agetty %I 38400
|
||||
Type=idle
|
||||
Restart=always
|
||||
RestartSec=0
|
||||
UtmpIdentifier=%I
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user