From 8166b06ac2243a9c741255803d4718153f3941f8 Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Mon, 16 Nov 2015 00:28:41 +0000 Subject: [PATCH] Use C++11 typesafe enums for service type (ServiceType) and state (ServiceState). --- load_service.cc | 8 ++--- service.cc | 88 ++++++++++++++++++++++++------------------------- service.h | 72 +++++++++++++++++++++------------------- 3 files changed, 86 insertions(+), 82 deletions(-) diff --git a/load_service.cc b/load_service.cc index 95fd5b0..67c2702 100644 --- a/load_service.cc +++ b/load_service.cc @@ -215,7 +215,7 @@ ServiceRecord * ServiceSet::loadServiceRecord(const char * name) const char ** commands = nullptr; int num_args = 0; - int service_type = SVC_PROCESS; + ServiceType service_type = ServiceType::PROCESS; std::list depends_on; std::list depends_soft; string logfile; @@ -280,13 +280,13 @@ ServiceRecord * ServiceSet::loadServiceRecord(const char * name) else if (setting == "type") { string type_str = read_setting_value(i, end); if (type_str == "scripted") { - service_type = SVC_SCRIPTED; + service_type = ServiceType::SCRIPTED; } else if (type_str == "process") { - service_type = SVC_PROCESS; + service_type = ServiceType::PROCESS; } else if (type_str == "internal") { - service_type = SVC_INTERNAL; + service_type = ServiceType::INTERNAL; } else { throw ServiceDescriptionExc(name, "Service type must be \"scripted\"" diff --git a/service.cc b/service.cc index 6bc34e1..60f1b7f 100644 --- a/service.cc +++ b/service.cc @@ -48,10 +48,10 @@ void ServiceSet::stopService(const std::string & name) // 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(); } @@ -59,7 +59,7 @@ void ServiceRecord::stopped() service_set->service_inactive(this); // TODO inform listeners. - if (desired_state == SVC_STARTED) { + if (desired_state == ServiceState::STARTED) { // Desired state is "started". start(); } @@ -74,12 +74,12 @@ void ServiceRecord::process_child_callback(struct ev_loop *loop, ev_child *w, in // 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 { @@ -90,8 +90,8 @@ void ServiceRecord::process_child_callback(struct ev_loop *loop, ev_child *w, in 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(); } @@ -103,7 +103,7 @@ void ServiceRecord::process_child_callback(struct ev_loop *loop, ev_child *w, in sr->stopped(); } } - else { // SVC_STARTING + else { // STARTING if (w->rstatus == 0) { sr->started(); } @@ -117,8 +117,8 @@ void ServiceRecord::process_child_callback(struct ev_loop *loop, ev_child *w, in 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 @@ -126,9 +126,9 @@ void ServiceRecord::start() } 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; @@ -141,17 +141,17 @@ void ServiceRecord::start() 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; @@ -164,7 +164,7 @@ void ServiceRecord::start() 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; } @@ -181,10 +181,10 @@ void ServiceRecord::start() } // 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(); @@ -193,7 +193,7 @@ void ServiceRecord::start() 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(1, "start")); if (! start_success) { @@ -208,18 +208,18 @@ void ServiceRecord::start() 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(); } } @@ -231,18 +231,18 @@ void ServiceRecord::started() 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(); @@ -385,19 +385,19 @@ void ServiceRecord::forceStop() // 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(); @@ -407,7 +407,7 @@ void ServiceRecord::failed_dependency() 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(); @@ -417,19 +417,19 @@ void ServiceRecord::dependentStopped() 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. @@ -452,7 +452,7 @@ bool ServiceRecord::stopCheckDependents() { 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; } @@ -465,7 +465,7 @@ bool ServiceRecord::stopDependents() { 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(); } @@ -479,9 +479,9 @@ bool ServiceRecord::stopDependents() // 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); diff --git a/service.h b/service.h index f47f73a..2a55c71 100644 --- a/service.h +++ b/service.h @@ -7,40 +7,44 @@ * 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: @@ -115,9 +119,9 @@ class ServiceRecord 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. @@ -196,16 +200,16 @@ class ServiceRecord 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; @@ -244,14 +248,14 @@ class ServiceRecord } 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; } }; @@ -293,11 +297,11 @@ class ServiceSet // 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 *); -- 2.25.1