// Tokenize the command, and add additional arguments from pargs:
vector<string> progAndArgs = tokenize(program_name);
progAndArgs.insert(progAndArgs.end(), pargs.begin(), pargs.end());
-
+
const char * pname = progAndArgs[0].c_str();
const char ** args = new const char *[progAndArgs.size() + 1];
void ServiceRecord::dependentStopped()
{
if (service_state != SVC_STOPPED && (desired_state == SVC_STOPPED || force_stop)) {
- bool all_deps_stopped = true;
- for (sr_iter i = dependents.begin(); i != dependents.end(); ++i) {
- if ((*i)->service_state != SVC_STOPPED) {
- all_deps_stopped = false;
- break;
- }
- }
-
- if (all_deps_stopped) {
+ // Check the other dependents before we stop.
+ if (stopCheckDependents()) {
stopping();
}
}
// TODO inform listeners waiting for start of cancellation
}
+ if (desired_state == SVC_STOPPED) return;
+
desired_state = SVC_STOPPED;
if (service_state != SVC_STARTED) {
+ if (service_state == SVC_STARTING) {
+ // Well this is awkward: we're going to have to continue
+ // starting, but we don't want any dependents to think that
+ // they are still waiting to start.
+ // Make sure they remain stopped:
+ stopDependents();
+ }
+
// If we're starting we need to wait for that to complete.
// If we're already stopping/stopped there's nothing to do.
return;
}
-
- // Make sure all dependents have stopped.
+ // If we get here, we are in STARTED state; stop all dependents.
+ if (stopCheckDependents()) {
+ stopping();
+ }
+}
+
+bool ServiceRecord::stopCheckDependents()
+{
bool all_deps_stopped = true;
for (sr_iter i = dependents.begin(); i != dependents.end(); ++i) {
if ((*i)->service_state != SVC_STOPPED) {
all_deps_stopped = false;
- (*i)->stop();
+ break;
}
}
- if (! all_deps_stopped) {
- // The dependents will notify this service once they've stopped.
- return;
+ return all_deps_stopped;
+}
+
+bool ServiceRecord::stopDependents()
+{
+ bool all_deps_stopped = true;
+ for (sr_iter i = dependents.begin(); i != dependents.end(); ++i) {
+ if ((*i)->service_state != SVC_STOPPED) {
+ all_deps_stopped = false;
+ (*i)->stop();
+ }
}
- // Ok, dependents have stopped. We can stop ourselves.
- stopping();
+ return all_deps_stopped;
}
+
+
// Dependency stopped or is stopping; we must stop too.
void ServiceRecord::stopping()
{
#include <vector>
#include "ev.h"
-/* Possible service states */
+/*
+ * Possible service states
+ *
+ * Services have both a current state and a desired state. The desired state can be
+ * either SVC_STARTED or SVC_STOPPED. The current state can also be SVC_STARTING
+ * or SVC_STOPPING.
+ *
+ * The total state is a combination of the two, current and desired:
+ * SVC_STOPPED/SVC_STOPPED : stopped and will remain stopped
+ * SVC_STOPPED/SVC_STARTED : stopped and will be started; waiting for dependencies to start.
+ * SVC_STARTING/SVC_STARTED : starting, but not yet started. All dependencies have started already.
+ * SVC_STARTING/SVC_STOPPED : as above, but the service will be stopped again as soon as it has
+ * completed startup.
+ * SVC_STARTED/SVC_STARTED : running and will continue running.
+ * SVC_STARTED/SVC_STOPPED : running but will stop; waiting for dependents to stop.
+ * SVC_STOPPING/SVC_STOPPED : stopping and will stop. All dependents have stopped.
+ * SVC_STOPPING/SVC_STARTED : as above, but the service will be re-started again once it stops.
+ *
+ * A scripted service is in the STARTING/STOPPING states during the script execution.
+ * A process service is in the STOPPING state when it has been signalled to stop (and is never
+ * in the STARTING state; it moves directly from STOPPED to STARTED).
+ */
// TODO can we use typesafe enum?
constexpr static int SVC_STOPPED = 0; // service is not running
-constexpr static int SVC_STARTING = 1; // service script is running with "start"
-constexpr static int SVC_STARTED = 2; // service is running; start script finished.
-constexpr static int SVC_STOPPING = 3; // service script is running with "stop"
+constexpr static int SVC_STARTING = 1; // service is starting, and will start (or fail to start) in time. All dependencies have started.
+constexpr static int SVC_STARTED = 2; // service is running
+constexpr static int SVC_STOPPING = 3; // service script is stopping and will stop.
/* Service types */
static void process_child_callback(struct ev_loop *loop, struct ev_child *w,
int revents);
- void dependentStopped(); // called when a dependent stopped
+ // A dependent has reached STOPPED state
+ void dependentStopped();
+
+ // check if all dependents have stopped
+ bool stopCheckDependents();
+
+ // issue a stop to all dependents, return true if they are all already stopped
+ bool stopDependents();
void forceStop(); // force-stop this service and all dependents