auto service_state = get_state();
if (service_state == service_state_t::STOPPING) {
+ // We might be running the stop script, or we might be running the start script and have issued
+ // a cancel order via SIGINT:
if (did_exit && WEXITSTATUS(exit_status) == 0) {
- stopped();
+ if (interrupting_start) {
+ interrupting_start = false;
+ // launch stop script:
+ bring_down();
+ }
+ else {
+ // We were running the stop script and finished successfully
+ stopped();
+ }
}
else {
- // ??? failed to stop! Let's log it as info:
- if (did_exit) {
- log(loglevel_t::INFO, "Service ", get_name(), " stop command failed with exit code ",
- WEXITSTATUS(exit_status));
+ if (interrupting_start) {
+ // We issued a start interrupt, so we expected this failure:
+ if (did_exit) {
+ log(loglevel_t::INFO, "Service ", get_name(), " start cancelled; exit code ",
+ WEXITSTATUS(exit_status));
+ }
+ else if (was_signalled) {
+ log(loglevel_t::INFO, "Service ", get_name(), " start cancelled from signal ",
+ WTERMSIG(exit_status));
+ }
}
- else if (was_signalled) {
- log(loglevel_t::INFO, "Service ", get_name(), " stop command terminated due to signal ",
- WTERMSIG(exit_status));
+ else {
+ // ??? failed to stop! Let's log it as warning:
+ if (did_exit) {
+ log(loglevel_t::WARN, "Service ", get_name(), " stop command failed with exit code ",
+ WEXITSTATUS(exit_status));
+ }
+ else if (was_signalled) {
+ log(loglevel_t::WARN, "Service ", get_name(), " stop command terminated due to signal ",
+ WTERMSIG(exit_status));
+ }
}
// Just assume that we stopped, so that any dependencies
// can be stopped:
+ interrupting_start = false;
stopped();
}
services->process_queues();
}
if (! interrupt_start()) {
- // Now wait for service startup to actually end
+ // Now wait for service startup to actually end; we don't need to handle it here.
return;
}
}
// Interrupt startup. Returns true if service start is fully cancelled; returns false if cancel order
- // issued but service has not yet responded.
+ // issued but service has not yet responded (state will be set to STOPPING).
virtual bool interrupt_start() noexcept;
public:
bool tracking_child : 1; // whether we expect to see child process status
bool start_is_interruptible : 1; // whether we can interrupt start
- // Start the process, return true on success
- virtual bool bring_up() noexcept override;
-
// Launch the process with the given arguments, return true on success
bool start_ps_process(const std::vector<const char *> &args, bool on_console) noexcept;
// Perform smooth recovery process
void do_smooth_recovery() noexcept;
+ // Start the process, return true on success
+ virtual bool bring_up() noexcept override;
+
virtual void bring_down() noexcept override;
// Called when the process exits. The exit_status is the status value yielded by
// the "wait" system call.
virtual void handle_exit_status(int exit_status) noexcept = 0;
+
+ // Called if an exec fails.
virtual void exec_failed(int errcode) noexcept = 0;
virtual bool can_interrupt_start() noexcept override
virtual void exec_failed(int errcode) noexcept override;
virtual void bring_down() noexcept override;
+ virtual bool interrupt_start() noexcept override
+ {
+ // if base::interrupt_start() returns false, then start hasn't been fully interrupted, but an
+ // interrupt has been issued:
+ interrupting_start = ! base_process_service::interrupt_start();
+ return ! interrupting_start;
+ }
+
+ bool interrupting_start : 1; // running start script (true) or stop script (false)
+
public:
scripted_service(service_set *sset, string name, string &&command,
std::list<std::pair<unsigned,unsigned>> &command_offsets,
std::list<prelim_dep> depends_p)
: base_process_service(sset, name, service_type_t::SCRIPTED, std::move(command), command_offsets,
- depends_p)
+ depends_p), interrupting_start(false)
{
}