Allow for interrupting process startup (by sending SIGINT).
authorDavin McCall <davmac@davmac.org>
Fri, 5 Jan 2018 20:09:28 +0000 (20:09 +0000)
committerDavin McCall <davmac@davmac.org>
Fri, 5 Jan 2018 20:09:28 +0000 (20:09 +0000)
src/service.cc
src/service.h
src/tests/test_service.h

index bbbe37a98559cb1f64b45a694d31bd62ba26d3e1..a3af696248eed977b6aa554b61291a9462709d5d 100644 (file)
@@ -1163,21 +1163,23 @@ void service_record::do_stop() noexcept
         if (required_by == 0) return; // release will re-call us anyway
     }
 
+    bool all_deps_stopped = stop_dependents();
+
     if (service_state != service_state_t::STARTED) {
         if (service_state == service_state_t::STARTING) {
             if (! can_interrupt_start()) {
-                // 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.
-                // Make sure they remain stopped:
-                stop_dependents();
+                // Well this is awkward: we're going to have to continue starting. We can stop once we've
+                // reached the started state.
+                return;
+            }
+
+            if (! interrupt_start()) {
+                // Now wait for service startup to actually end
                 return;
             }
 
             // We must have had desired_state == STARTED.
             notify_listeners(service_event_t::STARTCANCELLED);
-            
-            interrupt_start();
 
             // Reaching this point, we are starting interruptibly - so we
             // stop now (by falling through to below).
@@ -1191,7 +1193,7 @@ void service_record::do_stop() noexcept
 
     service_state = service_state_t::STOPPING;
     waiting_for_deps = true;
-    if (stop_dependents()) {
+    if (all_deps_stopped) {
         services->add_transition_queue(this);
     }
 }
@@ -1368,9 +1370,10 @@ void service_record::release_console() noexcept
     services->pull_console_queue();
 }
 
-void service_record::interrupt_start() noexcept
+bool service_record::interrupt_start() noexcept
 {
     services->unqueue_console(this);
+    return true;
 }
 
 void service_set::service_active(service_record *sr) noexcept
@@ -1407,6 +1410,7 @@ base_process_service::base_process_service(service_set *sset, string name,
     reserved_child_watch = false;
     tracking_child = false;
     stop_timer_armed = false;
+    start_is_interruptible = false;
 }
 
 void base_process_service::do_restart() noexcept
@@ -1478,20 +1482,24 @@ bool base_process_service::restart_ps_process() noexcept
     return true;
 }
 
-void base_process_service::interrupt_start() noexcept
+bool base_process_service::interrupt_start() noexcept
 {
-    // overridden in subclasses
     if (waiting_restart_timer) {
         restart_timer.stop_timer(eventLoop);
         waiting_restart_timer = false;
+        return service_record::interrupt_start();
+    }
+    else {
+        log(loglevel_t::WARN, "Interrupting start of service ", get_name(), " with pid ", pid, " (with SIGINT).");
+        kill_pg(SIGINT);
+        return false;
     }
-    service_record::interrupt_start();
 }
 
 void base_process_service::kill_with_fire() noexcept
 {
     if (pid != -1) {
-        log(loglevel_t::WARN, "Service ", get_name(), "with pid ", pid, " exceeded allowed stop time; killing.");
+        log(loglevel_t::WARN, "Service ", get_name(), " with pid ", pid, " exceeded allowed stop time; killing.");
         kill_pg(SIGKILL);
     }
 }
index e06eff59ce0a490bd05feca61356b1ba759d3044..f6bfed1c3bf001fc89b5c79a7aabf6c956c272f8 100644 (file)
@@ -451,7 +451,9 @@ class service_record
         return true;
     }
 
-    virtual void interrupt_start() noexcept;
+    // Interrupt startup. Returns true if service start is fully cancelled; returns false if cancel order
+    // issued but service has not yet responded.
+    virtual bool interrupt_start() noexcept;
 
     public:
 
@@ -669,7 +671,7 @@ class base_process_service : public service_record
 
     virtual bool can_interrupt_start() noexcept override
     {
-        return waiting_restart_timer || service_record::can_interrupt_start();
+        return waiting_restart_timer || start_is_interruptible || service_record::can_interrupt_start();
     }
 
     virtual bool can_proceed_to_start() noexcept override
@@ -677,7 +679,7 @@ class base_process_service : public service_record
         return ! waiting_restart_timer;
     }
 
-    virtual void interrupt_start() noexcept override;
+    virtual bool interrupt_start() noexcept override;
 
     // Kill with SIGKILL
     void kill_with_fire() noexcept;
index 3593ceebb2ec280e9d8692a141af44c24115576b..eeb7605365c750f1dbe0227053cacfed5d5f5372 100644 (file)
@@ -30,9 +30,9 @@ class test_service : public service_record
         return waiting_for_deps;
     }
 
-    virtual void interrupt_start() noexcept override
+    virtual bool interrupt_start() noexcept override
     {
-
+        return true;
     }
 
     void started() noexcept