Code consistency and documentation update
authorDavin McCall <davmac@davmac.org>
Sun, 12 Jun 2016 09:00:49 +0000 (10:00 +0100)
committerDavin McCall <davmac@davmac.org>
Sun, 12 Jun 2016 09:00:49 +0000 (10:00 +0100)
src/service.cc
src/service.h

index b3bbf16e5bba5f22c70e37a2e3576d9c8d400305..5827e23a313cc8084cf38d25020c9517934b5e4b 100644 (file)
@@ -69,17 +69,20 @@ void ServiceRecord::stopped() noexcept
         releaseConsole();
     }
 
-    logServiceStopped(service_name);
     service_state = ServiceState::STOPPED;
     force_stop = false;
     
+    logServiceStopped(service_name);
     notifyListeners(ServiceEvent::STOPPED);
     
+    bool will_restart = (desired_state == ServiceState::STARTED) && service_set->get_auto_restart();
     for (auto dependency : depends_on) {
-        dependency->dependentStopped();
+        if (! will_restart || ! dependency->can_interrupt_stop()) {
+            dependency->dependentStopped();
+        }
     }
     
-    if (desired_state == ServiceState::STARTED && service_set->get_auto_restart()) {
+    if (will_restart) {
         // Desired state is "started".
         do_start();
     }
@@ -150,7 +153,7 @@ void ServiceRecord::handle_exit_status() noexcept
         if (need_stop) {
             // Failed startup: no auto-restart.
             desired_state = ServiceState::STOPPED;
-            do_stop();
+            forceStop();
         }
         
         return;
@@ -305,15 +308,16 @@ void ServiceRecord::release_dependencies() noexcept
 
 void ServiceRecord::start(bool activate) noexcept
 {
-    if (activate) {
-        if (!start_explicit) require();
+    if (activate && ! start_explicit) {
+        require();
         start_explicit = true;
     }
     
     if (desired_state == ServiceState::STARTED && service_state != ServiceState::STOPPED) return;
     
     if (required_by == 0) {
-        service_set->service_active(this);
+        // It really doesn't make any sense to start if there is no dependent or explicit activation.
+        return;
     }
 
     desired_state = ServiceState::STARTED;
@@ -753,7 +757,7 @@ void ServiceRecord::stop(bool bring_down) noexcept
         release();
     }
     
-    if (bring_down) {
+    if (bring_down && desired_state != ServiceState::STOPPED) {
         desired_state = ServiceState::STOPPED;
         do_stop();
     }
@@ -829,7 +833,7 @@ bool ServiceRecord::stopDependents() noexcept
     return all_deps_stopped;
 }
 
-// All dependents have stopped; we can stop now, too.
+// All dependents have stopped; we can stop now, too. Only called when STOPPING.
 void ServiceRecord::allDepsStopped()
 {
     waiting_for_deps = false;
@@ -850,7 +854,7 @@ void ServiceRecord::allDepsStopped()
                 int status;
                 pid_t r = waitpid(pid, &status, WNOHANG);
                 if (r == -1 && errno == ECHILD) {
-                    // We can't track this child
+                    // We can't track this child (or it's terminated already)
                     stopped();
                 }
                 else if (r == pid) {
@@ -884,7 +888,7 @@ void ServiceRecord::unpin() noexcept
     if (pinned_started) {
         pinned_started = false;
         if (desired_state == ServiceState::STOPPED) {
-            stop();
+            do_stop();
         }
     }
     if (pinned_stopped) {
index 2cd5a007fcb3c6768cd059dc8cef118b89302eef..4775fcf5b24a494d79f63ee4b931531941671cd5 100644 (file)
  * each dependent service which is not STOPPED (including depdendents with a soft dependency).
  * When required_by transitions to 0, the service is stopped (unless it is pinned). When
  * require_by transitions from 0, the service is started (unless pinned).
+ *
+ * So, in general, the dependent-count determines the desired state (STARTED if the count
+ * is greater than 0, otherwise STOPPED). However, a service can be issued a stop-and-take
+ * down order (via `stop(true)'); this will first stop dependent services, which may restart
+ * and cancel the stop of the former service. Finally, a service can be force-stopped, which
+ * means that its stop process cannot be cancelled (though it may still be put in a desired
+ * state of STARTED, meaning it will start immediately upon stopping).
+ *
+ * Pinning
+ * -------
+ * A service may be "pinned" in either STARTED or STOPPED states (or even both). Once it
+ * reaches a pinned state, a service will not leave that state, though its desired state
+ * may still be set. (Note that pinning prevents, but never causes, state transition).
+ *
+ * The priority of the different state deciders is:
+ *  - pins
+ *  - force stop flag
+ *  - desired state (which is manipulated by require/release operations)
+ *
+ * So a forced stop cannot occur until the service is not pinned started, for instance.
  */
 
 struct OnstartFlags {
@@ -294,8 +314,11 @@ class ServiceRecord
             int revents) noexcept;
     
     void handle_exit_status() noexcept;
-    
+
+    // Called on transition of desired state from stopped to started (or unpinned stop)
     void do_start() noexcept;
+
+    // Called on transition of desired state from started to stopped (or unpinned start)
     void do_stop() noexcept;
     
     // A dependency has reached STARTED state