Add possibility to pin services started or stopped. This prevents
authorDavin McCall <davmac@davmac.org>
Tue, 1 Dec 2015 19:53:33 +0000 (19:53 +0000)
committerDavin McCall <davmac@davmac.org>
Tue, 1 Dec 2015 19:53:33 +0000 (19:53 +0000)
them from automatically stopping or starting as part of a dependency
chain.

service.cc
service.h

index 291ae22d26fe696e84ac8d53e1c3f6faa90500d1..dcda52d6f4e6cb8c8adcdde12b273759057a2556 100644 (file)
@@ -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++;
index 3f6295ebb4e135967d06c7f4803b97d87e34aed1..1c8963f1b2de2c103d469b96396e44fee0fd2ec0 100644 (file)
--- a/service.h
+++ b/service.h
  *
  * 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<ServiceRecord *> 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<std::pair<unsigned,unsigned>> &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
     {