Skip to content

Commit

Permalink
shutdown: make kill timeout configurable (#7835)
Browse files Browse the repository at this point in the history
By default systemd-shutdown will wait for 90s after SIGTERM was sent
for all processes to exit. This is way too long and effectively defeats
an emergency watchdog reboot via "reboot-force" actions. Instead now
use DefaultTimeoutStopSec which is configurable.
  • Loading branch information
jkloetzke authored and poettering committed Jan 10, 2018
1 parent 0a7eed9 commit e73c54b
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 11 deletions.
8 changes: 4 additions & 4 deletions src/core/killall.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,15 @@ static bool ignore_proc(pid_t pid, bool warn_rootfs) {
return true;
}

static void wait_for_children(Set *pids, sigset_t *mask) {
static void wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
usec_t until;

assert(mask);

if (set_isempty(pids))
return;

until = now(CLOCK_MONOTONIC) + DEFAULT_TIMEOUT_USEC;
until = now(CLOCK_MONOTONIC) + timeout;
for (;;) {
struct timespec ts;
int k;
Expand Down Expand Up @@ -221,7 +221,7 @@ static int killall(int sig, Set *pids, bool send_sighup) {
return set_size(pids);
}

void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup) {
void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout) {
sigset_t mask, oldmask;
_cleanup_set_free_ Set *pids = NULL;

Expand All @@ -241,7 +241,7 @@ void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup) {
log_warning_errno(errno, "kill(-1, SIGCONT) failed: %m");

if (wait_for_exit)
wait_for_children(pids, &mask);
wait_for_children(pids, &mask, timeout);

assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
}
4 changes: 3 additions & 1 deletion src/core/killall.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/

void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup);
#include "time-util.h"

void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout);
11 changes: 7 additions & 4 deletions src/core/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1467,24 +1467,27 @@ static int become_shutdown(
int retval) {

char log_level[DECIMAL_STR_MAX(int) + 1],
exit_code[DECIMAL_STR_MAX(uint8_t) + 1];
exit_code[DECIMAL_STR_MAX(uint8_t) + 1],
timeout[DECIMAL_STR_MAX(usec_t) + 1];

const char* command_line[11] = {
const char* command_line[13] = {
SYSTEMD_SHUTDOWN_BINARY_PATH,
shutdown_verb,
"--timeout", timeout,
"--log-level", log_level,
"--log-target",
};

_cleanup_strv_free_ char **env_block = NULL;
size_t pos = 5;
size_t pos = 7;
int r;

assert(shutdown_verb);
assert(!command_line[pos]);
env_block = strv_copy(environ);

xsprintf(log_level, "%d", log_get_max_level());
xsprintf(timeout, "%" PRI_USEC "us", arg_default_timeout_stop_usec);

switch (log_get_target()) {

Expand Down Expand Up @@ -1640,7 +1643,7 @@ static void do_reexecute(
if (switch_root_dir) {
/* Kill all remaining processes from the initrd, but don't wait for them, so that we can handle the
* SIGCHLD for them after deserializing. */
broadcast_signal(SIGTERM, false, true);
broadcast_signal(SIGTERM, false, true, arg_default_timeout_stop_usec);

/* And switch root with MS_MOVE, because we remove the old directory afterwards and detach it. */
r = switch_root(switch_root_dir, "/mnt", true, MS_MOVE);
Expand Down
14 changes: 12 additions & 2 deletions src/core/shutdown.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@

static char* arg_verb;
static uint8_t arg_exit_code;
static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;

static int parse_argv(int argc, char *argv[]) {
enum {
Expand All @@ -66,6 +67,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_LOG_COLOR,
ARG_LOG_LOCATION,
ARG_EXIT_CODE,
ARG_TIMEOUT,
};

static const struct option options[] = {
Expand All @@ -74,6 +76,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "log-color", optional_argument, NULL, ARG_LOG_COLOR },
{ "log-location", optional_argument, NULL, ARG_LOG_LOCATION },
{ "exit-code", required_argument, NULL, ARG_EXIT_CODE },
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
{}
};

Expand Down Expand Up @@ -129,6 +132,13 @@ static int parse_argv(int argc, char *argv[]) {

break;

case ARG_TIMEOUT:
r = parse_sec(optarg, &arg_timeout);
if (r < 0)
log_error("Failed to parse shutdown timeout %s, ignoring", optarg);

break;

case '\001':
if (!arg_verb)
arg_verb = optarg;
Expand Down Expand Up @@ -327,10 +337,10 @@ int main(int argc, char *argv[]) {
disable_core_dumps();

log_info("Sending SIGTERM to remaining processes...");
broadcast_signal(SIGTERM, true, true);
broadcast_signal(SIGTERM, true, true, arg_timeout);

log_info("Sending SIGKILL to remaining processes...");
broadcast_signal(SIGKILL, true, false);
broadcast_signal(SIGKILL, true, false, arg_timeout);

need_umount = !in_container;
need_swapoff = !in_container;
Expand Down

0 comments on commit e73c54b

Please sign in to comment.