chiark / gitweb /
execute: make kill mode configurable
authorLennart Poettering <lennart@poettering.net>
Wed, 7 Apr 2010 22:52:14 +0000 (00:52 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 7 Apr 2010 22:52:14 +0000 (00:52 +0200)
cgroup.c
cgroup.h
load-fragment.c
service.c
service.h
socket.c
socket.h
unit.c
unit.h

index 9e1b0de..24bbe1a 100644 (file)
--- 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
index 66ddb95..b7e18bf 100644 (file)
--- 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;
 
index bd84e8f..f24950c 100644 (file)
@@ -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"),
index 8a00349..7ed9783 100644 (file)
--- 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. */
index 1a170f5..fa81e98 100644 (file)
--- a/service.h
+++ b/service.h
@@ -94,6 +94,8 @@ struct Service {
 
         ServiceState state;
 
+        KillMode kill_mode;
+
         ExecStatus main_exec_status;
 
         ExecCommand *control_command;
index a1f3ef8..4e35225 100644 (file)
--- 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);
index 356341f..f821186 100644 (file)
--- 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 93c0d8d..e6331b4 100644 (file)
--- 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 942de5f..9def661 100644 (file)
--- 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