On interrupted start, unlink from console wait queue.
authorDavin McCall <davmac@davmac.org>
Mon, 12 Jun 2017 20:45:00 +0000 (21:45 +0100)
committerDavin McCall <davmac@davmac.org>
Mon, 12 Jun 2017 20:45:00 +0000 (21:45 +0100)
src/dinit-ll.h
src/dinit-log.cc
src/service.cc
src/service.h

index 6abb8d3be16d02e7275a2250c4f4f7270e57b04c..4e16d2874ef4baf72a1523b32edcc1dce7f52f4d 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef DINIT_LL_INCLUDED
 #define DINIT_LL_INCLUDED 1
 
-// Simple doubly-linked list implementation, where the contained element includes the
-// list node. This allows a single item to be a member of several different kinds of
-// list, without requiring dynamicall allocation of nodes.
+// Simple single- and doubly-linked list implementation, where the contained element includes the
+// list node. This allows a single item to be a member of several different kinds of list, without
+// requiring dynamic allocation of nodes.
 
 template <typename T>
 struct lld_node
@@ -88,6 +88,22 @@ class dlist
         }
         return r;
     }
+
+    void unlink(T *record) noexcept
+    {
+        auto &node = E(record);
+        if (first == record) {
+            first = node.next;
+            if (first == record) {
+                // unlinking the only node in the list:
+                first = nullptr;
+            }
+        }
+        E(node.next).prev = node.prev;
+        E(node.prev).next = node.next;
+        node.next = nullptr;
+        node.prev = nullptr;
+    }
 };
 
 template <typename T, lls_node<T> &(*E)(T *)>
index 7a8db587c3fccda77d8b018745097139f6744e2e..68bbcedfe25a6a55b5afceca093a580303ef6a18 100644 (file)
@@ -109,7 +109,7 @@ void BufferedLogStream::release_console()
     if (release) {
         int flags = fcntl(1, F_GETFL, 0);
         fcntl(1, F_SETFL, flags & ~O_NONBLOCK);
-        service_set->pullConsoleQueue();
+        service_set->pull_console_queue();
     }
 }
 
index d1d5160d27a636e229103a5c1e372a0542fd86ea..c31dcbcd91d2b1cfaad380b40ec81b6de2cc3e95 100644 (file)
@@ -1032,6 +1032,8 @@ void ServiceRecord::do_stop() noexcept
             // We must have had desired_state == STARTED.
             notifyListeners(ServiceEvent::STARTCANCELLED);
             
+            interrupt_start();
+
             // Reaching this point, we are starting interruptibly - so we
             // stop now (by falling through to below).
         }
@@ -1165,7 +1167,12 @@ void ServiceRecord::queue_for_console() noexcept
 
 void ServiceRecord::release_console() noexcept
 {
-    service_set->pullConsoleQueue();
+    service_set->pull_console_queue();
+}
+
+void ServiceRecord::interrupt_start() noexcept
+{
+    service_set->unqueue_console(this);
 }
 
 void ServiceSet::service_active(ServiceRecord *sr) noexcept
@@ -1280,6 +1287,7 @@ void base_process_service::interrupt_start() noexcept
         restart_timer.stop_timer(eventLoop);
         waiting_restart_timer = false;
     }
+    ServiceRecord::interrupt_start();
 }
 
 dasynq::rearm process_restart_timer::timer_expiry(EventLoop_t &, int expiry_count)
index 2a9774aa0b6fc7f41c49c7784333311fd0269bf4..8b052d857eadc14fec8aecac026b20b2d623d67c 100644 (file)
@@ -369,10 +369,7 @@ class ServiceRecord
         return waiting_for_deps;
     }
     
-    virtual void interrupt_start() noexcept
-    {
-        // overridden in subclasses
-    }
+    virtual void interrupt_start() noexcept;
 
     // Whether a STOPPING service can immediately transition to STARTED.
     bool can_interrupt_stop() noexcept
@@ -422,7 +419,8 @@ class ServiceRecord
     public:
 
     ServiceRecord(ServiceSet *set, string name)
-        : service_state(ServiceState::STOPPED), desired_state(ServiceState::STOPPED), auto_restart(false),
+        : service_state(ServiceState::STOPPED), desired_state(ServiceState::STOPPED),
+            auto_restart(false), smooth_recovery(false),
             pinned_stopped(false), pinned_started(false), waiting_for_deps(false),
             waiting_for_execstat(false), start_explicit(false),
             prop_require(false), prop_release(false), prop_failure(false),
@@ -879,11 +877,18 @@ class ServiceSet
     }
     
     // Retrieve the current console queue head and remove it from the queue
-    ServiceRecord * pullConsoleQueue() noexcept
+    ServiceRecord * pull_console_queue() noexcept
     {
         return console_queue.pop_front();
     }
     
+    void unqueue_console(ServiceRecord * service) noexcept
+    {
+        if (console_queue.is_queued(service)) {
+            console_queue.unlink(service);
+        }
+    }
+
     // Notification from service that it is active (state != STOPPED)
     // Only to be called on the transition from inactive to active.
     void service_active(ServiceRecord *) noexcept;