summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Kasick <mike@kasick.org>2012-02-06 10:32:13 -0500
committerMike Kasick <mike@kasick.org>2012-03-22 22:11:41 -0400
commit7e36edd80f23a5d34ce7b5b0fbe8ecfea061a826 (patch)
treea1e04e8149c4beaada883e0b3546aa3d87cf7c87
parentef3eb5f74022050666168922d96c79531401a16d (diff)
downloadsystem_core-7e36edd80f23a5d34ce7b5b0fbe8ecfea061a826.zip
system_core-7e36edd80f23a5d34ce7b5b0fbe8ecfea061a826.tar.gz
system_core-7e36edd80f23a5d34ce7b5b0fbe8ecfea061a826.tar.bz2
init: Safely restart services to avoid race conditions.
Previously, service restarts (either an explicit "restart", or a "stop, start" pair) exhibited a race condition whereby the new (restarting) service process was often spawned before the old (stopping) process had terminated. This may have resulted in the new service process failing to acquire a limited resource (file lock, socket bind, etc.) that the old process had not yet released. Now, a stopping service remains in the SVC_RUNNING state until its exiting process has been reaped by waitpid. This prevents a "stop, start" sequence from spawning a second service process before resources held by the first are released. This enables safe service restarts by stopping the service, waiting for the old service process to terminate, and (only then) starting the new service process. In the event of "restarting" an already stopped service, the previous behavior is maintained whereby the service is simply started. This scenario could be special-cased by the restart command, however, we have observed instances where services are, unintentionally, stopped and started "too quickly," and so simultaneous processes for the same service should never be allowed. Note that this commit alters the behaviors for explicit restarts of critical and oneshot services. Previously these serivces would simply be restarted, whereas now, an explicit restart of a critical service counts as a crash (which may result in a recovery reboot) and oneshot services go into the disabled state.
-rwxr-xr-xinit/init.c7
1 files changed, 3 insertions, 4 deletions
diff --git a/init/init.c b/init/init.c
index 1ee88a7..e0f2cf7 100755
--- a/init/init.c
+++ b/init/init.c
@@ -369,10 +369,9 @@ void service_start(struct service *svc, const char *dynamic_args)
/* The how field should be either SVC_DISABLED or SVC_RESET */
static void service_stop_or_reset(struct service *svc, int how)
{
- /* we are no longer running, nor should we
- * attempt to restart
- */
- svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING));
+ /* The service is still SVC_RUNNING until its process exits, but if it has
+ * already exited it shoudn't attempt a restart yet. */
+ svc->flags &= (~SVC_RESTARTING);
if ((how != SVC_DISABLED) && (how != SVC_RESET)) {
/* Hrm, an illegal flag. Default to SVC_DISABLED */