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).
service_state = service_state_t::STOPPING;
waiting_for_deps = true;
- if (stop_dependents()) {
+ if (all_deps_stopped) {
services->add_transition_queue(this);
}
}
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
reserved_child_watch = false;
tracking_child = false;
stop_timer_armed = false;
+ start_is_interruptible = false;
}
void base_process_service::do_restart() 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);
}
}
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:
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
return ! waiting_restart_timer;
}
- virtual void interrupt_start() noexcept override;
+ virtual bool interrupt_start() noexcept override;
// Kill with SIGKILL
void kill_with_fire() noexcept;