summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgroup.c24
-rw-r--r--cgroup.h3
-rw-r--r--load-fragment.c28
-rw-r--r--service.c47
-rw-r--r--service.h2
-rw-r--r--socket.c23
-rw-r--r--socket.h2
-rw-r--r--unit.c8
-rw-r--r--unit.h15
9 files changed, 125 insertions, 27 deletions
diff --git a/cgroup.c b/cgroup.c
index 9e1b0de379..24bbe1aa15 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 66ddb9579a..b7e18bf620 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 bd84e8fe79..f24950c70d 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 8a0034936f..7ed9783f79 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 1a170f526f..fa81e98a74 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 a1f3ef8af7..4e3522505f 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 356341f2a6..f821186ec9 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 93c0d8d61a..e6331b44d3 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 942de5f36f..9def661ce1 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