mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-03-13 12:58:20 +03:00
systemd: do not output status messages once gettys are running
Make Type=idle communication bidirectional: when bootup is finished, the manager, as before, signals idling Type=idle jobs to continue. However, if the boot takes too long, idling jobs signal the manager that they have had enough, wait a tiny bit more, and continue, taking ownership of the console. The manager, when signalled that Type=idle jobs are done, makes a note and will not write to the console anymore. This is a cosmetic issue, but quite noticable, so let's just fix it. Based on Harald Hoyer's patch. https://bugs.freedesktop.org/show_bug.cgi?id=54247 http://unix.stackexchange.com/questions/51805/systemd-messages-after-starting-login/
This commit is contained in:
parent
77a9e8de65
commit
31a7eb86f1
@ -69,6 +69,7 @@
|
||||
#include "unit.h"
|
||||
|
||||
#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
|
||||
#define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC)
|
||||
|
||||
/* This assumes there is a 'tty' group */
|
||||
#define TTY_MODE 0620
|
||||
@ -977,6 +978,35 @@ static int apply_seccomp(uint32_t *syscall_filter) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_idle_pipe_dance(int idle_pipe[4]) {
|
||||
assert(idle_pipe);
|
||||
|
||||
if (idle_pipe[1] >= 0)
|
||||
close_nointr_nofail(idle_pipe[1]);
|
||||
if (idle_pipe[2] >= 0)
|
||||
close_nointr_nofail(idle_pipe[2]);
|
||||
|
||||
if (idle_pipe[0] >= 0) {
|
||||
int r;
|
||||
|
||||
r = fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT_USEC);
|
||||
|
||||
if (idle_pipe[3] >= 0 && r == 0 /* timeout */) {
|
||||
/* Signal systemd that we are bored and want to continue. */
|
||||
write(idle_pipe[3], "x", 1);
|
||||
|
||||
/* Wait for systemd to react to the signal above. */
|
||||
fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC);
|
||||
}
|
||||
|
||||
close_nointr_nofail(idle_pipe[0]);
|
||||
|
||||
}
|
||||
|
||||
if (idle_pipe[3] >= 0)
|
||||
close_nointr_nofail(idle_pipe[3]);
|
||||
}
|
||||
|
||||
int exec_spawn(ExecCommand *command,
|
||||
char **argv,
|
||||
ExecContext *context,
|
||||
@ -989,7 +1019,7 @@ int exec_spawn(ExecCommand *command,
|
||||
CGroupControllerMask cgroup_mask,
|
||||
const char *cgroup_path,
|
||||
const char *unit_id,
|
||||
int idle_pipe[2],
|
||||
int idle_pipe[4],
|
||||
pid_t *ret) {
|
||||
|
||||
_cleanup_strv_free_ char **files_env = NULL;
|
||||
@ -1083,14 +1113,8 @@ 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, IDLE_TIMEOUT_USEC);
|
||||
close_nointr_nofail(idle_pipe[0]);
|
||||
}
|
||||
}
|
||||
if (idle_pipe)
|
||||
do_idle_pipe_dance(idle_pipe);
|
||||
|
||||
/* Close sockets very early to make sure we don't
|
||||
* block init reexecution because it cannot bind its
|
||||
|
@ -273,6 +273,58 @@ static void manager_print_jobs_in_progress(Manager *m) {
|
||||
m->jobs_in_progress_iteration++;
|
||||
}
|
||||
|
||||
static int manager_watch_idle_pipe(Manager *m) {
|
||||
struct epoll_event ev = {
|
||||
.events = EPOLLIN,
|
||||
.data.ptr = &m->idle_pipe_watch,
|
||||
};
|
||||
int r;
|
||||
|
||||
if (m->idle_pipe_watch.type != WATCH_INVALID)
|
||||
return 0;
|
||||
|
||||
if (m->idle_pipe[2] < 0)
|
||||
return 0;
|
||||
|
||||
m->idle_pipe_watch.type = WATCH_IDLE_PIPE;
|
||||
m->idle_pipe_watch.fd = m->idle_pipe[2];
|
||||
if (m->idle_pipe_watch.fd < 0) {
|
||||
log_error("Failed to create timerfd: %m");
|
||||
r = -errno;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->idle_pipe_watch.fd, &ev) < 0) {
|
||||
log_error("Failed to add idle_pipe fd to epoll: %m");
|
||||
r = -errno;
|
||||
goto err;
|
||||
}
|
||||
|
||||
log_debug("Set up idle_pipe watch.");
|
||||
log_debug("m->epoll_fd=%d m->idle_pipe_watch.fd=%d",
|
||||
m->epoll_fd, m->idle_pipe_watch.fd);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (m->idle_pipe_watch.fd >= 0)
|
||||
close_nointr_nofail(m->idle_pipe_watch.fd);
|
||||
watch_init(&m->idle_pipe_watch);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void manager_unwatch_idle_pipe(Manager *m) {
|
||||
if (m->idle_pipe_watch.type != WATCH_IDLE_PIPE)
|
||||
return;
|
||||
|
||||
log_debug("m->epoll_fd=%d m->idle_pipe_watch.fd=%d",
|
||||
m->epoll_fd, m->idle_pipe_watch.fd);
|
||||
assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, m->idle_pipe_watch.fd, NULL) >= 0);
|
||||
watch_init(&m->idle_pipe_watch);
|
||||
|
||||
log_debug("Closed idle_pipe watch.");
|
||||
}
|
||||
|
||||
static int manager_setup_time_change(Manager *m) {
|
||||
struct epoll_event ev = {
|
||||
.events = EPOLLIN,
|
||||
@ -445,7 +497,7 @@ int manager_new(SystemdRunningAs running_as, bool reexecuting, 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;
|
||||
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
|
||||
|
||||
watch_init(&m->signal_watch);
|
||||
watch_init(&m->mount_watch);
|
||||
@ -657,6 +709,11 @@ static void manager_clear_jobs_and_units(Manager *m) {
|
||||
m->n_running_jobs = 0;
|
||||
}
|
||||
|
||||
static void close_idle_pipe(Manager *m) {
|
||||
close_pipe(m->idle_pipe);
|
||||
close_pipe(m->idle_pipe + 2);
|
||||
}
|
||||
|
||||
void manager_free(Manager *m) {
|
||||
UnitType c;
|
||||
int i;
|
||||
@ -701,7 +758,7 @@ void manager_free(Manager *m) {
|
||||
hashmap_free(m->cgroup_unit);
|
||||
set_free_free(m->unit_path_cache);
|
||||
|
||||
close_pipe(m->idle_pipe);
|
||||
close_idle_pipe(m);
|
||||
|
||||
free(m->switch_root);
|
||||
free(m->switch_root_init);
|
||||
@ -1138,6 +1195,9 @@ unsigned manager_dispatch_run_queue(Manager *m) {
|
||||
if (m->n_running_jobs > 0)
|
||||
manager_watch_jobs_in_progress(m);
|
||||
|
||||
if (m->n_on_console > 0)
|
||||
manager_watch_idle_pipe(m);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -1691,6 +1751,14 @@ static int process_event(Manager *m, struct epoll_event *ev) {
|
||||
break;
|
||||
}
|
||||
|
||||
case WATCH_IDLE_PIPE: {
|
||||
m->no_console_output = true;
|
||||
|
||||
manager_unwatch_idle_pipe(m);
|
||||
close_idle_pipe(m);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
log_error("event type=%i", w->type);
|
||||
assert_not_reached("Unknown epoll event type.");
|
||||
@ -2384,7 +2452,8 @@ void manager_check_finished(Manager *m) {
|
||||
}
|
||||
|
||||
/* Notify Type=idle units that we are done now */
|
||||
close_pipe(m->idle_pipe);
|
||||
manager_unwatch_idle_pipe(m);
|
||||
close_idle_pipe(m);
|
||||
|
||||
/* Turn off confirm spawn now */
|
||||
m->confirm_spawn = false;
|
||||
@ -2660,6 +2729,9 @@ static bool manager_get_show_status(Manager *m) {
|
||||
if (m->running_as != SYSTEMD_SYSTEM)
|
||||
return false;
|
||||
|
||||
if (m->no_console_output)
|
||||
return false;
|
||||
|
||||
if (m->show_status)
|
||||
return true;
|
||||
|
||||
|
@ -63,7 +63,8 @@ enum WatchType {
|
||||
WATCH_DBUS_WATCH,
|
||||
WATCH_DBUS_TIMEOUT,
|
||||
WATCH_TIME_CHANGE,
|
||||
WATCH_JOBS_IN_PROGRESS
|
||||
WATCH_JOBS_IN_PROGRESS,
|
||||
WATCH_IDLE_PIPE,
|
||||
};
|
||||
|
||||
struct Watch {
|
||||
@ -135,6 +136,7 @@ struct Manager {
|
||||
Watch signal_watch;
|
||||
Watch time_change_watch;
|
||||
Watch jobs_in_progress_watch;
|
||||
Watch idle_pipe_watch;
|
||||
|
||||
int epoll_fd;
|
||||
|
||||
@ -227,6 +229,7 @@ struct Manager {
|
||||
|
||||
bool show_status;
|
||||
bool confirm_spawn;
|
||||
bool no_console_output;
|
||||
|
||||
ExecOutput default_std_output, default_std_error;
|
||||
|
||||
@ -244,7 +247,7 @@ struct Manager {
|
||||
unsigned jobs_in_progress_iteration;
|
||||
|
||||
/* Type=idle pipes */
|
||||
int idle_pipe[2];
|
||||
int idle_pipe[4];
|
||||
|
||||
char *switch_root;
|
||||
char *switch_root_init;
|
||||
|
@ -733,8 +733,11 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e
|
||||
* feature for cosmetics, not actually useful for
|
||||
* anything beyond that. */
|
||||
|
||||
if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0)
|
||||
if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 &&
|
||||
m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) {
|
||||
pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
|
||||
pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1425,10 +1425,14 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
|
||||
if (UNIT_IS_INACTIVE_OR_FAILED(os) != UNIT_IS_INACTIVE_OR_FAILED(ns)) {
|
||||
ExecContext *ec = unit_get_exec_context(u);
|
||||
if (ec && exec_context_may_touch_console(ec)) {
|
||||
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
|
||||
m->n_on_console--;
|
||||
else
|
||||
m->n_on_console++;
|
||||
if (UNIT_IS_INACTIVE_OR_FAILED(ns)) {
|
||||
m->n_on_console --;
|
||||
|
||||
if (m->n_on_console == 0)
|
||||
/* unset no_console_output flag, since the console is free */
|
||||
m->no_console_output = 0;
|
||||
} else
|
||||
m->n_on_console ++;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user