From 4741fb0e5bf01b33ca8e131a095e978940c3f33f Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Mon, 12 Jun 2017 21:45:00 +0100 Subject: [PATCH] On interrupted start, unlink from console wait queue. --- src/dinit-ll.h | 22 +++++++++++++++++++--- src/dinit-log.cc | 2 +- src/service.cc | 10 +++++++++- src/service.h | 17 +++++++++++------ 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/dinit-ll.h b/src/dinit-ll.h index 6abb8d3..4e16d28 100644 --- a/src/dinit-ll.h +++ b/src/dinit-ll.h @@ -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 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 &(*E)(T *)> diff --git a/src/dinit-log.cc b/src/dinit-log.cc index 7a8db58..68bbced 100644 --- a/src/dinit-log.cc +++ b/src/dinit-log.cc @@ -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(); } } diff --git a/src/service.cc b/src/service.cc index d1d5160..c31dcbc 100644 --- a/src/service.cc +++ b/src/service.cc @@ -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) diff --git a/src/service.h b/src/service.h index 2a9774a..8b052d8 100644 --- a/src/service.h +++ b/src/service.h @@ -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; -- 2.25.1