summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2011-01-20 18:46:38 +0100
committerLennart Poettering <lennart@poettering.net>2011-01-20 18:46:38 +0100
commit867b3b7d6b88ba4d07ec7c830576d4ac2f7dd226 (patch)
tree8dd046309411ed5a53e0c1c78433d9ce57ced33a /src
parentc06b7a15ea4bd9a6063eb16e1b4ee77ef05714b4 (diff)
service: make chain of main commands and control commands independent of each other, so that both can be executed simultaneously and independently
Diffstat (limited to 'src')
-rw-r--r--src/service.c66
-rw-r--r--src/service.h10
2 files changed, 52 insertions, 24 deletions
diff --git a/src/service.c b/src/service.c
index 03a858a4ae..60576dfed7 100644
--- a/src/service.c
+++ b/src/service.c
@@ -211,6 +211,7 @@ static void service_done(Unit *u) {
exec_context_done(&s->exec_context);
exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
s->control_command = NULL;
+ s->main_command = NULL;
/* This will leak a process, but at least no memory or any of
* our resources */
@@ -1400,8 +1401,10 @@ static void service_set_state(Service *s, ServiceState state) {
state != SERVICE_RELOAD &&
state != SERVICE_STOP &&
state != SERVICE_STOP_SIGTERM &&
- state != SERVICE_STOP_SIGKILL)
+ state != SERVICE_STOP_SIGKILL) {
service_unwatch_main_pid(s);
+ s->main_command = NULL;
+ }
if (state != SERVICE_START_PRE &&
state != SERVICE_START &&
@@ -1782,8 +1785,9 @@ static void service_enter_stop_post(Service *s, bool success) {
service_unwatch_control_pid(s);
- s->control_command_id = SERVICE_EXEC_STOP_POST;
if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) {
+ s->control_command_id = SERVICE_EXEC_STOP_POST;
+
if ((r = service_spawn(s,
s->control_command,
true,
@@ -1901,8 +1905,9 @@ static void service_enter_stop(Service *s, bool success) {
service_unwatch_control_pid(s);
- s->control_command_id = SERVICE_EXEC_STOP;
if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) {
+ s->control_command_id = SERVICE_EXEC_STOP;
+
if ((r = service_spawn(s,
s->control_command,
true,
@@ -1950,8 +1955,9 @@ static void service_enter_start_post(Service *s) {
service_unwatch_control_pid(s);
- s->control_command_id = SERVICE_EXEC_START_POST;
if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) {
+ s->control_command_id = SERVICE_EXEC_START_POST;
+
if ((r = service_spawn(s,
s->control_command,
true,
@@ -1977,6 +1983,7 @@ fail:
static void service_enter_start(Service *s) {
pid_t pid;
int r;
+ ExecCommand *c;
assert(s);
@@ -1988,11 +1995,20 @@ static void service_enter_start(Service *s) {
else
service_unwatch_main_pid(s);
- s->control_command_id = SERVICE_EXEC_START;
- s->control_command = s->exec_command[SERVICE_EXEC_START];
+ if (s->type == SERVICE_FORKING) {
+ s->control_command_id = SERVICE_EXEC_START;
+ c = s->control_command = s->exec_command[SERVICE_EXEC_START];
+
+ s->main_command = NULL;
+ } else {
+ s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
+ s->control_command = NULL;
+
+ c = s->main_command = s->exec_command[SERVICE_EXEC_START];
+ }
if ((r = service_spawn(s,
- s->control_command,
+ c,
s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY,
true,
true,
@@ -2047,8 +2063,9 @@ static void service_enter_start_pre(Service *s) {
service_unwatch_control_pid(s);
- s->control_command_id = SERVICE_EXEC_START_PRE;
if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) {
+ s->control_command_id = SERVICE_EXEC_START_PRE;
+
if ((r = service_spawn(s,
s->control_command,
true,
@@ -2107,8 +2124,9 @@ static void service_enter_reload(Service *s) {
service_unwatch_control_pid(s);
- s->control_command_id = SERVICE_EXEC_RELOAD;
if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) {
+ s->control_command_id = SERVICE_EXEC_RELOAD;
+
if ((r = service_spawn(s,
s->control_command,
true,
@@ -2182,20 +2200,18 @@ static void service_run_next_main(Service *s, bool success) {
int r;
assert(s);
- assert(s->control_command);
- assert(s->control_command->command_next);
+ assert(s->main_command);
+ assert(s->main_command->command_next);
+ assert(s->type == SERVICE_ONESHOT);
if (!success)
s->failure = true;
- assert(s->control_command_id == SERVICE_EXEC_START);
- assert(s->type == SERVICE_ONESHOT);
-
- s->control_command = s->control_command->command_next;
+ s->main_command = s->main_command->command_next;
service_unwatch_main_pid(s);
if ((r = service_spawn(s,
- s->control_command,
+ s->main_command,
false,
true,
true,
@@ -2510,10 +2526,14 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->main_pid = 0;
exec_status_exit(&s->main_exec_status, pid, code, status, s->exec_context.utmp_id);
- if (s->type != SERVICE_FORKING && s->control_command) {
- s->control_command->exec_status = s->main_exec_status;
+ /* If this is not a forking service than the main
+ * process got started and hence we copy the exit
+ * status so that it is recorded both as main and as
+ * control process exit status */
+ if (s->main_command) {
+ s->main_command->exec_status = s->main_exec_status;
- if (s->control_command->ignore)
+ if (s->main_command->ignore)
success = true;
}
@@ -2521,8 +2541,8 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
"%s: main process exited, code=%s, status=%i", u->meta.id, sigchld_code_to_string(code), status);
s->failure = s->failure || !success;
- if (s->control_command &&
- s->control_command->command_next &&
+ if (s->main_command &&
+ s->main_command->command_next &&
success) {
/* There is another command to *
@@ -2535,9 +2555,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
/* The service exited, so the service is officially
* gone. */
-
- s->control_command = NULL;
- s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
+ s->main_command = NULL;
switch (s->state) {
diff --git a/src/service.h b/src/service.h
index 758604621e..e06ff3d45a 100644
--- a/src/service.h
+++ b/src/service.h
@@ -103,10 +103,20 @@ struct Service {
ServiceState state, deserialized_state;
+ /* The exit status of the real main process */
ExecStatus main_exec_status;
+ /* The currently executed control process */
ExecCommand *control_command;
+
+ /* The currently executed main process, which may be NULL if
+ * the main process got started via forking mode and not by
+ * us */
+ ExecCommand *main_command;
+
+ /* The ID of the control command currently being executed */
ServiceExecCommand control_command_id;
+
pid_t main_pid, control_pid;
int socket_fd;