From 50159e6a776143be076f8ebe73a8a59447050698 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 8 Apr 2010 00:52:14 +0200 Subject: [PATCH] execute: make kill mode configurable --- cgroup.c | 24 ++++++++++++++++++++---- cgroup.h | 3 --- load-fragment.c | 28 ++++++++++++++++++++++++++++ service.c | 47 ++++++++++++++++++++++++++++++++--------------- service.h | 2 ++ socket.c | 23 ++++++++++++++++++++--- socket.h | 2 ++ unit.c | 8 ++++++++ unit.h | 15 +++++++++++++-- 9 files changed, 125 insertions(+), 27 deletions(-) diff --git a/cgroup.c b/cgroup.c index 9e1b0de3..24bbe1aa 100644 --- a/cgroup.c +++ b/cgroup.c @@ -174,13 +174,19 @@ int cgroup_bonding_kill(CGroupBonding *b, int sig) { int r; Set *s; bool done; + bool killed = false; assert(b); assert(sig > 0); + if (!b->only_us) + return -EAGAIN; + if (!(s = set_new(trivial_hash_func, trivial_compare_func))) return -ENOMEM; + log_debug("Killing processes from process group %s:%s", b->controller, b->path); + do { void *iterator; pid_t pid; @@ -208,6 +214,7 @@ int cgroup_bonding_kill(CGroupBonding *b, int sig) { break; } + killed = true; done = false; if ((r = set_put(s, INT_TO_PTR(pid))) < 0) @@ -235,20 +242,29 @@ int cgroup_bonding_kill(CGroupBonding *b, int sig) { } while (!done && r >= 0); set_free(s); - return r; + + if (r < 0) + return r; + + return killed ? 0 : -ESRCH; } int cgroup_bonding_kill_list(CGroupBonding *first, int sig) { CGroupBonding *b; + int r = -EAGAIN; LIST_FOREACH(by_unit, b, first) { - int r; + if ((r = cgroup_bonding_kill(b, sig)) < 0) { + if (r == -EAGAIN || -ESRCH) + continue; - if ((r = cgroup_bonding_kill(b, sig)) < 0) return r; + } + + return 0; } - return 0; + return r; } /* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we diff --git a/cgroup.h b/cgroup.h index 66ddb957..b7e18bf6 100644 --- a/cgroup.h +++ b/cgroup.h @@ -37,9 +37,6 @@ struct CGroupBonding { struct cgroup *cgroup; - /* When shutting down, kill all tasks? */ - bool kill_all:1; - /* When shutting down, remove cgroup? */ bool clean_up:1; diff --git a/load-fragment.c b/load-fragment.c index bd84e8fe..f24950c7 100644 --- a/load-fragment.c +++ b/load-fragment.c @@ -979,6 +979,32 @@ static int config_parse_sysv_priority( return 0; } +static int config_parse_kill_mode( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + const char *rvalue, + void *data, + void *userdata) { + + KillMode *m = data, x; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if ((x = kill_mode_from_string(rvalue)) < 0) { + log_error("[%s:%u] Failed to parse kill mode specifier: %s", filename, line, rvalue); + return -EBADMSG; + } + + *m = x; + + return 0; +} + #define FOLLOW_MAX 8 static int open_follow(char **filename, FILE **_f, Set *names, char **_id) { @@ -1177,6 +1203,7 @@ static int load_from_path(Unit *u, const char *path, UnitLoadState *new_state) { { "RootDirectoryStartOnly", config_parse_bool, &u->service.root_directory_start_only, "Service" }, { "ValidNoProcess", config_parse_bool, &u->service.valid_no_process, "Service" }, { "SysVStartPriority", config_parse_sysv_priority, &u->service.sysv_start_priority, "Service" }, + { "KillMode", config_parse_kill_mode, &u->service.kill_mode, "Service" }, EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"), { "ListenStream", config_parse_listen, &u->socket, "Socket" }, @@ -1192,6 +1219,7 @@ static int load_from_path(Unit *u, const char *path, UnitLoadState *new_state) { { "ExecStopPost", config_parse_exec, u->socket.exec_command+SOCKET_EXEC_STOP_POST, "Socket" }, { "DirectoryMode", config_parse_mode, &u->socket.directory_mode, "Socket" }, { "SocketMode", config_parse_mode, &u->socket.socket_mode, "Socket" }, + { "KillMode", config_parse_kill_mode, &u->socket.kill_mode, "Socket" }, EXEC_CONTEXT_CONFIG_ITEMS(u->socket.exec_context, "Socket"), EXEC_CONTEXT_CONFIG_ITEMS(u->automount.exec_context, "Automount"), diff --git a/service.c b/service.c index 8a003493..7ed9783f 100644 --- a/service.c +++ b/service.c @@ -700,8 +700,12 @@ static int service_init(Unit *u, UnitLoadState *new_state) { s->sysv_start_priority = -1; s->permissions_start_only = false; s->root_directory_start_only = false; - + s->valid_no_process = false; + s->kill_mode = 0; s->sysv_has_lsb = false; + s->main_pid = s->control_pid = 0; + s->main_pid_known = false; + s->failure = false; RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5); @@ -755,11 +759,13 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) { "%sPermissionsStartOnly: %s\n" "%sRootDirectoryStartOnly: %s\n" "%sValidNoProcess: %s\n" + "%sKillMode: %s\n" "%sType: %s\n", prefix, service_state_to_string(s->state), prefix, yes_no(s->permissions_start_only), prefix, yes_no(s->root_directory_start_only), prefix, yes_no(s->valid_no_process), + prefix, kill_mode_to_string(s->kill_mode), prefix, service_type_to_string(s->type)); if (s->pid_file) @@ -1154,23 +1160,34 @@ static void service_enter_signal(Service *s, ServiceState state, bool success) { sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? SIGTERM : SIGKILL; - r = 0; - if (s->main_pid > 0) { - if (kill(s->main_pid, sig) < 0 && errno != ESRCH) - r = -errno; - else - sent = true; - } + if (s->kill_mode == KILL_CONTROL_GROUP) { - if (s->control_pid > 0) { - if (kill(s->control_pid, sig) < 0 && errno != ESRCH) - r = -errno; - else + if ((r = cgroup_bonding_kill_list(UNIT(s)->meta.cgroup_bondings, sig)) < 0) { + if (r != -EAGAIN && r != -ESRCH) + goto fail; + } else sent = true; } - if (r < 0) - goto fail; + if (!sent) { + r = 0; + if (s->main_pid > 0) { + if (kill(s->kill_mode == KILL_PROCESS ? s->main_pid : -s->main_pid, sig) < 0 && errno != ESRCH) + r = -errno; + else + sent = true; + } + + if (s->control_pid > 0) { + if (kill(s->kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH) + r = -errno; + else + sent = true; + } + + if (r < 0) + goto fail; + } } service_set_state(s, state); @@ -1538,7 +1555,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { s->exec_command[SERVICE_EXEC_START]->exec_status = s->main_exec_status; } - log_debug("%s: main process exited, code=%s status=%i", unit_id(u), sigchld_code_to_string(code), status); + log_debug("%s: main process exited, code=%s, status=%i", unit_id(u), sigchld_code_to_string(code), status); /* The service exited, so the service is officially * gone. */ diff --git a/service.h b/service.h index 1a170f52..fa81e98a 100644 --- a/service.h +++ b/service.h @@ -94,6 +94,8 @@ struct Service { ServiceState state; + KillMode kill_mode; + ExecStatus main_exec_status; ExecCommand *control_command; diff --git a/socket.c b/socket.c index a1f3ef8a..4e352250 100644 --- a/socket.c +++ b/socket.c @@ -109,6 +109,9 @@ static int socket_init(Unit *u, UnitLoadState *new_state) { s->timeout_usec = DEFAULT_TIMEOUT_USEC; s->directory_mode = 0755; s->socket_mode = 0666; + s->kill_mode = 0; + s->failure = false; + s->control_pid = 0; exec_context_init(&s->exec_context); if ((r = unit_load_fragment(u, new_state)) < 0) @@ -183,11 +186,13 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sSocket State: %s\n" "%sBindIPv6Only: %s\n" "%sBacklog: %u\n" + "%sKillMode: %s\n" "%sSocketMode: %04o\n" "%sDirectoryMode: %04o\n", prefix, state_string_table[s->state], prefix, yes_no(s->bind_ipv6_only), prefix, s->backlog, + prefix, kill_mode_to_string(s->kill_mode), prefix, s->socket_mode, prefix, s->directory_mode); @@ -471,13 +476,25 @@ static void socket_enter_signal(Socket *s, SocketState state, bool success) { if (s->control_pid > 0) { int sig; + bool sent = false; sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_POST_SIGTERM) ? SIGTERM : SIGKILL; - if (kill(s->control_pid, sig) < 0 && errno != ESRCH) { - r = -errno; - goto fail; + if (s->kill_mode == KILL_CONTROL_GROUP) { + + if ((r = cgroup_bonding_kill_list(UNIT(s)->meta.cgroup_bondings, sig)) < 0) { + if (r != -EAGAIN && r != -ESRCH) + goto fail; + } else + sent = true; } + + if (!sent) + if (kill(s->kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH) { + r = -errno; + goto fail; + } + } socket_set_state(s, state); diff --git a/socket.h b/socket.h index 356341f2..f821186e 100644 --- a/socket.h +++ b/socket.h @@ -89,6 +89,8 @@ struct Socket { SocketState state; + KillMode kill_mode; + ExecCommand* control_command; pid_t control_pid; diff --git a/unit.c b/unit.c index 93c0d8d6..e6331b44 100644 --- a/unit.c +++ b/unit.c @@ -1439,3 +1439,11 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency); + +static const char* const kill_mode_table[_KILL_MODE_MAX] = { + [KILL_PROCESS] = "process", + [KILL_PROCESS_GROUP] = "process-group", + [KILL_CONTROL_GROUP] = "control-group" +}; + +DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode); diff --git a/unit.h b/unit.h index 942de5f3..9def661c 100644 --- a/unit.h +++ b/unit.h @@ -43,6 +43,14 @@ typedef enum UnitDependency UnitDependency; #define DEFAULT_TIMEOUT_USEC (20*USEC_PER_SEC) #define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC) +typedef enum KillMode { + KILL_CONTROL_GROUP = 0, + KILL_PROCESS_GROUP, + KILL_PROCESS, + _KILL_MODE_MAX, + _KILL_MODE_INVALID = -1 +} KillMode; + enum UnitType { UNIT_SERVICE = 0, UNIT_TIMER, @@ -53,7 +61,7 @@ enum UnitType { UNIT_AUTOMOUNT, UNIT_SNAPSHOT, _UNIT_TYPE_MAX, - _UNIT_TYPE_INVALID = -1, + _UNIT_TYPE_INVALID = -1 }; enum UnitLoadState { @@ -314,6 +322,8 @@ int set_unit_path(const char *p); char *unit_name_escape_path(const char *path, const char *suffix); +char *unit_dbus_path(Unit *u); + const char *unit_type_to_string(UnitType i); UnitType unit_type_from_string(const char *s); @@ -326,6 +336,7 @@ UnitActiveState unit_active_state_from_string(const char *s); const char *unit_dependency_to_string(UnitDependency i); UnitDependency unit_dependency_from_string(const char *s); -char *unit_dbus_path(Unit *u); +const char *kill_mode_to_string(KillMode k); +KillMode kill_mode_from_string(const char *s); #endif -- 2.39.5