From 438f9cb15c3da4980891840447c670ce6c93d435 Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Tue, 1 Dec 2015 19:53:33 +0000 Subject: [PATCH] Add possibility to pin services started or stopped. This prevents them from automatically stopping or starting as part of a dependency chain. --- service.cc | 42 ++++++++++++++++++++++++++++++++++++++---- service.h | 24 ++++++++++++++++-------- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/service.cc b/service.cc index 291ae22..dcda52d 100644 --- a/service.cc +++ b/service.cc @@ -120,7 +120,7 @@ void ServiceRecord::process_child_callback(struct ev_loop *loop, ev_child *w, in } } -void ServiceRecord::start() noexcept +void ServiceRecord::start(bool unpinned) noexcept { if ((service_state == ServiceState::STARTING || service_state == ServiceState::STARTED) && desired_state == ServiceState::STOPPED) { @@ -130,7 +130,7 @@ void ServiceRecord::start() noexcept // its cancellation } - if (desired_state == ServiceState::STARTED) return; + if (desired_state == ServiceState::STARTED && !unpinned) return; desired_state = ServiceState::STARTED; @@ -140,6 +140,8 @@ void ServiceRecord::start() noexcept return; } + if (pinned_stopped) return; + service_state = ServiceState::STARTING; service_set->service_active(this); @@ -445,7 +447,7 @@ void ServiceRecord::dependentStopped() noexcept } } -void ServiceRecord::stop() noexcept +void ServiceRecord::stop(bool unpinned) noexcept { if ((service_state == ServiceState::STOPPING || service_state == ServiceState::STOPPED) && desired_state == ServiceState::STARTED) { @@ -454,9 +456,11 @@ void ServiceRecord::stop() noexcept // TODO inform listeners waiting for start of cancellation } - if (desired_state == ServiceState::STOPPED) return; + if (desired_state == ServiceState::STOPPED && !unpinned) return; desired_state = ServiceState::STOPPED; + + if (pinned_started) return; if (service_state != ServiceState::STARTED) { if (service_state == ServiceState::STARTING) { @@ -538,6 +542,36 @@ void ServiceRecord::allDepsStopped() } } +void ServiceRecord::pinStart() noexcept +{ + pinned_stopped = false; + start(); + pinned_started = true; +} + +void ServiceRecord::pinStop() noexcept +{ + pinned_started = false; + stop(); + pinned_stopped = true; +} + +void ServiceRecord::unpin() noexcept +{ + if (pinned_started) { + pinned_started = false; + if (desired_state == ServiceState::STOPPED) { + stop(true); + } + } + if (pinned_stopped) { + pinned_stopped = false; + if (desired_state == ServiceState::STARTED) { + start(true); + } + } +} + void ServiceSet::service_active(ServiceRecord *sr) noexcept { active_services++; diff --git a/service.h b/service.h index 3f6295e..1c8963f 100644 --- a/service.h +++ b/service.h @@ -10,15 +10,17 @@ * * Services have both a current state and a desired state. The desired state can be * either STARTED or STOPPED. The current state can also be STARTING or STOPPING. + * A service can be "pinned" in either the STARTED or STOPPED states to prevent it + * from leaving that state until it is unpinned. * * The total state is a combination of the two, current and desired: * STOPPED/STOPPED : stopped and will remain stopped - * STOPPED/STARTED : - (this state cannot occur) + * STOPPED/STARTED : stopped (pinned), must be unpinned to start * STARTING/STARTED : starting, but not yet started. Dependencies may also be starting. * 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 : - (this state cannot occur) + * STARTED/STOPPED : started (pinned), must be unpinned to stop * STOPPING/STOPPED : stopping and will stop. Dependents may be stopping. * STOPPING/STARTED : as above, but the service will be re-started again once it stops. * @@ -170,8 +172,9 @@ class ServiceRecord OnstartFlags onstart_flags; string logfile; /* log file name, empty string specifies /dev/null */ - bool auto_restart; /* whether to restart this (process) if it dies unexpectedly */ - + bool auto_restart : 1; /* whether to restart this (process) if it dies unexpectedly */ + bool pinned_stopped : 1; + bool pinned_started : 1; typedef std::list sr_list; typedef sr_list::iterator sr_iter; @@ -254,7 +257,8 @@ class ServiceRecord public: ServiceRecord(ServiceSet *set, string name) - : service_state(ServiceState::STOPPED), desired_state(ServiceState::STOPPED), auto_restart(false), force_stop(false) + : service_state(ServiceState::STOPPED), desired_state(ServiceState::STOPPED), auto_restart(false), + pinned_stopped(false), pinned_started(false), force_stop(false) { service_set = set; service_name = name; @@ -263,7 +267,7 @@ class ServiceRecord ServiceRecord(ServiceSet *set, string name, ServiceType service_type, string &&command, std::list> &command_offsets, sr_list * pdepends_on, sr_list * pdepends_soft) - : service_state(ServiceState::STOPPED), desired_state(ServiceState::STOPPED), auto_restart(false), force_stop(false) + : ServiceRecord(set, name) { service_set = set; service_name = name; @@ -316,8 +320,12 @@ class ServiceRecord const char *getServiceName() const noexcept { return service_name.c_str(); } ServiceState getState() const noexcept { return service_state; } - void start() noexcept; // start the service - void stop() noexcept; // stop the service + void start(bool unpinned = false) noexcept; // start the service + void stop(bool unpinned = false) noexcept; // stop the service + + void pinStart() noexcept; // start the service and pin it + void pinStop() noexcept; // stop the service and pin it + void unpin() noexcept; // unpin the service bool isDummy() noexcept { -- 2.25.1