// Called when a service has actually stopped.
void ServiceRecord::stopped()
{
- service_state = SVC_STOPPED;
+ service_state = ServiceState::STOPPED;
force_stop = false;
- // Stop any dependencies whose desired state is SVC_STOPPED:
+ // Stop any dependencies whose desired state is STOPPED:
for (sr_iter i = depends_on.begin(); i != depends_on.end(); i++) {
(*i)->dependentStopped();
}
service_set->service_inactive(this);
// TODO inform listeners.
- if (desired_state == SVC_STARTED) {
+ if (desired_state == ServiceState::STARTED) {
// Desired state is "started".
start();
}
// Ok, for a process service, any process death which we didn't rig
// ourselves is a bit... unexpected. Probably, the child died because
- // we asked it to (sr->service_state == SVC_STOPPING). But even if
+ // we asked it to (sr->service_state == STOPPING). But even if
// we didn't, there's not much we can do.
- if (sr->service_type == SVC_PROCESS) {
+ if (sr->service_type == ServiceType::PROCESS) {
// TODO log non-zero rstatus?
- if (sr->service_state == SVC_STOPPING) {
+ if (sr->service_state == ServiceState::STOPPING) {
sr->stopped();
}
else {
sr->start();
}
}
- else { // SVC_SCRIPTED
- if (sr->service_state == SVC_STOPPING) {
+ else { // SCRIPTED
+ if (sr->service_state == ServiceState::STOPPING) {
if (w->rstatus == 0) {
sr->stopped();
}
sr->stopped();
}
}
- else { // SVC_STARTING
+ else { // STARTING
if (w->rstatus == 0) {
sr->started();
}
void ServiceRecord::start()
{
- if ((service_state == SVC_STARTING || service_state == SVC_STARTED)
- && desired_state == SVC_STOPPED) {
+ if ((service_state == ServiceState::STARTING || service_state == ServiceState::STARTED)
+ && desired_state == ServiceState::STOPPED) {
// This service was starting, or started, but was set to be stopped.
// Cancel the stop (and continue starting/running).
// TODO any listeners waiting for stop should be notified of
}
auto old_desired_state = desired_state;
- desired_state = SVC_STARTED;
+ desired_state = ServiceState::STARTED;
- if (service_state == SVC_STARTED || service_state == SVC_STARTING) {
+ if (service_state == ServiceState::STARTED || service_state == ServiceState::STARTING) {
// We couldn't be started or starting unless all dependencies have
// already started: so there's nothing left to do.
return;
for (sr_iter i = depends_on.begin(); i != depends_on.end(); ++i) {
// Note, we cannot treat a dependency as started if its force_stop
// flag is set.
- if ((*i)->service_state != SVC_STARTED || (*i)->force_stop) {
+ if ((*i)->service_state != ServiceState::STARTED || (*i)->force_stop) {
all_deps_started = false;
(*i)->start();
}
}
- if (old_desired_state != SVC_STARTED) {
+ if (old_desired_state != ServiceState::STARTED) {
// This is a fresh start, so we mark all soft dependencies as 'waiting on' and ask them
// to start:
for (auto i = soft_deps.begin(); i != soft_deps.end(); ++i) {
- if (i->getTo()->service_state != SVC_STARTED) {
+ if (i->getTo()->service_state != ServiceState::STARTED) {
all_deps_started = false;
i->getTo()->start();
i->waiting_on = true;
for (auto i = soft_deps.begin(); i != soft_deps.end(); ++i) {
ServiceRecord * to = i->getTo();
if (i->waiting_on) {
- if ((to->desired_state != SVC_STARTED && to->service_state != SVC_STARTING) || to->service_state == SVC_STARTED) {
+ if ((to->desired_state != ServiceState::STARTED && to->service_state != ServiceState::STARTING) || to->service_state == ServiceState::STARTED) {
// Service has either started or is no longer starting
i->waiting_on = false;
}
}
// Actually start this service.
- service_state = SVC_STARTING;
+ service_state = ServiceState::STARTING;
service_set->service_active(this);
- if (service_type == SVC_PROCESS) {
+ if (service_type == ServiceType::PROCESS) {
bool start_success = start_ps_process();
if (start_success) {
started();
failed_to_start();
}
}
- else if (service_type == SVC_SCRIPTED) {
+ else if (service_type == ServiceType::SCRIPTED) {
// Script-controlled service
bool start_success = start_ps_process(std::vector<std::string>(1, "start"));
if (! start_success) {
void ServiceRecord::started()
{
- service_state = SVC_STARTED;
+ service_state = ServiceState::STARTED;
// TODO - inform listeners
- if (desired_state == SVC_STARTED) {
- // Start any dependents whose desired state is SVC_STARTED:
+ if (desired_state == ServiceState::STARTED) {
+ // Start any dependents whose desired state is STARTED:
for (auto i = dependents.begin(); i != dependents.end(); i++) {
- if ((*i)->desired_state == SVC_STARTED) {
+ if ((*i)->desired_state == ServiceState::STARTED) {
(*i)->start();
}
}
for (auto i = soft_dpts.begin(); i != soft_dpts.end(); i++) {
- if ((*i)->getFrom()->desired_state == SVC_STARTED) {
+ if ((*i)->getFrom()->desired_state == ServiceState::STARTED) {
(*i)->getFrom()->start();
}
}
void ServiceRecord::failed_to_start()
{
- service_state = SVC_STOPPED;
- desired_state = SVC_STOPPED;
+ service_state = ServiceState::STOPPED;
+ desired_state = ServiceState::STOPPED;
service_set->service_inactive(this);
// failure to start
// Cancel start of dependents:
for (sr_iter i = dependents.begin(); i != dependents.end(); i++) {
- if ((*i)->desired_state == SVC_STARTED) {
+ if ((*i)->desired_state == ServiceState::STARTED) {
(*i)->failed_dependency();
}
}
for (auto i = soft_dpts.begin(); i != soft_dpts.end(); i++) {
- if ((*i)->getFrom()->desired_state == SVC_STARTED) {
+ if ((*i)->getFrom()->desired_state == ServiceState::STARTED) {
// We can send 'start', because this is only a soft dependency.
// Our startup failure means that they don't have to wait for us.
(*i)->getFrom()->start();
// A dependency of this service failed to start.
void ServiceRecord::failed_dependency()
{
- desired_state = SVC_STOPPED;
+ desired_state = ServiceState::STOPPED;
// Presumably, we were starting. So now we're not.
- service_state = SVC_STOPPED;
+ service_state = ServiceState::STOPPED;
// Notify dependents of this service also
for (auto i = dependents.begin(); i != dependents.end(); i++) {
- if ((*i)->desired_state == SVC_STARTED) {
+ if ((*i)->desired_state == ServiceState::STARTED) {
(*i)->failed_dependency();
}
}
for (auto i = soft_dpts.begin(); i != soft_dpts.end(); i++) {
- if ((*i)->getFrom()->desired_state == SVC_STARTED) {
+ if ((*i)->getFrom()->desired_state == ServiceState::STARTED) {
// It's a soft dependency, so send them 'started' rather than
// 'failed dep'.
(*i)->getFrom()->started();
void ServiceRecord::dependentStopped()
{
- if (service_state != SVC_STOPPED && (desired_state == SVC_STOPPED || force_stop)) {
+ if (service_state != ServiceState::STOPPED && (desired_state == ServiceState::STOPPED || force_stop)) {
// Check the other dependents before we stop.
if (stopCheckDependents()) {
stopping();
void ServiceRecord::stop()
{
- if ((service_state == SVC_STOPPING || service_state == SVC_STOPPED)
- && desired_state == SVC_STARTED) {
+ if ((service_state == ServiceState::STOPPING || service_state == ServiceState::STOPPED)
+ && desired_state == ServiceState::STARTED) {
// The service *was* stopped/stopping, but it was going to restart.
// Now, we'll cancel the restart.
// TODO inform listeners waiting for start of cancellation
}
- if (desired_state == SVC_STOPPED) return;
+ if (desired_state == ServiceState::STOPPED) return;
- desired_state = SVC_STOPPED;
+ desired_state = ServiceState::STOPPED;
- if (service_state != SVC_STARTED) {
- if (service_state == SVC_STARTING) {
+ if (service_state != ServiceState::STARTED) {
+ if (service_state == ServiceState::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.
{
bool all_deps_stopped = true;
for (sr_iter i = dependents.begin(); i != dependents.end(); ++i) {
- if ((*i)->service_state != SVC_STOPPED) {
+ if ((*i)->service_state != ServiceState::STOPPED) {
all_deps_stopped = false;
break;
}
{
bool all_deps_stopped = true;
for (sr_iter i = dependents.begin(); i != dependents.end(); ++i) {
- if ((*i)->service_state != SVC_STOPPED) {
+ if ((*i)->service_state != ServiceState::STOPPED) {
all_deps_stopped = false;
(*i)->stop();
}
// Dependency stopped or is stopping; we must stop too.
void ServiceRecord::stopping()
{
- service_state = SVC_STOPPING;
+ service_state = ServiceState::STOPPING;
- if (service_type == SVC_PROCESS) {
+ if (service_type == ServiceType::PROCESS) {
if (pid != -1) {
// The process is still kicking on - must actually kill it.
kill(pid, SIGTERM);
* 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.
+ * either STARTED or STOPPED. The current state can also be STARTING or 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.
+ * STOPPED/STOPPED : stopped and will remain stopped
+ * STOPPED/STARTED : stopped and will be started; waiting for dependencies to start.
+ * STARTING/STARTED : starting, but not yet started. All dependencies have started already.
+ * STARTING/STOPPED : as above, but the service will be stopped again as soon as it has
+ * completed startup.
+ * STARTED/STARTED : running and will continue running.
+ * STARTED/STOPPED : running but will stop; waiting for dependents to stop.
+ * STOPPING/STOPPED : stopping and will stop. All dependents have stopped.
+ * STOPPING/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 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.
+enum class ServiceState {
+ STOPPED, // service is not running.
+ STARTING, // service is starting, and will start (or fail to start) in time. All dependencies have started.
+ STARTED, // service is running,
+ STOPPING // service script is stopping and will stop.
+};
+
/* Service types */
-#define SVC_DUMMY 0 /* dummy service, used to detect cyclic dependencies */
-#define SVC_PROCESS 1 /* service runs as a process, and can be stopped
- by sending the process a signal */
-#define SVC_SCRIPTED 2 /* service requires a command to start, and another
- command to stop */
-#define SVC_INTERNAL 3 /* internal service, runs no external process */
+enum class ServiceType {
+ DUMMY, // dummy service, used to detect cyclice dependencies
+ PROCESS, // service runs as a process, and can be stopped by
+ // sending the process a signal (SIGTERM)
+ SCRIPTED, // service requires an external command to start,
+ // and a second command to stop
+ INTERNAL // internal service, runs no external process
+};
+
-// Exception loading service
+// Exception while loading a service
class ServiceLoadExc
{
public:
typedef std::string string;
string service_name;
- int service_type; /* SVC_DAEMON or SVC_SCRIPTED */
- int service_state; /* SVC_STOPPED, _STARTING, _STARTED, _STOPPING */
- int desired_state; /* SVC_STOPPED / SVC_STARTED */
+ ServiceType service_type; /* ServiceType::DUMMY, PROCESS, SCRIPTED, INTERNAL */
+ ServiceState service_state; /* ServiceState::STOPPED, STARTING, STARTED, STOPPING */
+ ServiceState desired_state; /* ServiceState::STOPPED / STARTED */
bool force_stop; // true if the service must actually stop. This is the
// case if for example the process dies; the service,
// and all its dependencies, MUST be stopped.
public:
ServiceRecord(ServiceSet *set, string name)
- : service_state(SVC_STOPPED), desired_state(SVC_STOPPED), force_stop(false), auto_restart(false)
+ : service_state(ServiceState::STOPPED), desired_state(ServiceState::STOPPED), force_stop(false), auto_restart(false)
{
service_set = set;
service_name = name;
- service_type = SVC_DUMMY;
+ service_type = ServiceType::DUMMY;
}
- ServiceRecord(ServiceSet *set, string name, int service_type, string command, const char ** commands,
+ ServiceRecord(ServiceSet *set, string name, ServiceType service_type, string command, const char ** commands,
int num_argsx, sr_list * pdepends_on, sr_list * pdepends_soft)
- : service_state(SVC_STOPPED), desired_state(SVC_STOPPED), force_stop(false), auto_restart(false)
+ : service_state(ServiceState::STOPPED), desired_state(ServiceState::STOPPED), force_stop(false), auto_restart(false)
{
service_set = set;
service_name = name;
}
const char *getServiceName() const { return service_name.c_str(); }
- int getState() const { return service_state; }
+ ServiceState getState() const { return service_state; }
void start(); // start the service
void stop(); // stop the service
bool isDummy()
{
- return service_type == SVC_DUMMY;
+ return service_type == ServiceType::DUMMY;
}
};
// transition to the 'stopped' state.
void stopService(const std::string &name);
- // Notification from service that it is active (state != SVC_STOPPED)
+ // Notification from service that it is active (state != STOPPED)
// Only to be called on the transition from inactive to active.
void service_active(ServiceRecord *);
- // Notification from service that it is inactive (SVC_STOPPED)
+ // Notification from service that it is inactive (STOPPED)
// Only to be called on the transition from active to inactive.
void service_inactive(ServiceRecord *);