return false;
}
+void ServiceRecord::emergency_stop() noexcept
+{
+ if (! do_auto_restart() && start_explicit) {
+ start_explicit = false;
+ release();
+ }
+ forceStop();
+ stopDependents();
+ stopped();
+}
+
void process_service::handle_exit_status(int exit_status) noexcept
{
bool did_exit = WIFEXITED(exit_status);
// that dependencies have started before trying to re-start the
// service process.
if (! restart_ps_process()) {
- desired_state = ServiceState::STOPPED;
- forceStop();
+ emergency_stop();
+ service_set->processQueues(false);
}
return;
}
else {
- if (! do_auto_restart()) desired_state = ServiceState::STOPPED;
- forceStop();
+ emergency_stop();
}
service_set->processQueues(false);
}
if (need_stop) {
// Failed startup: no auto-restart.
- desired_state = ServiceState::STOPPED;
- forceStop();
+ emergency_stop();
service_set->processQueues(false);
}
// service process.
doing_recovery = true;
if (! restart_ps_process()) {
- desired_state = ServiceState::STOPPED;
- forceStop();
+ emergency_stop();
+ service_set->processQueues();
}
return;
}
else {
- if (! do_auto_restart()) desired_state = ServiceState::STOPPED;
+ // we must be STARTED
+ if (! do_auto_restart() && start_explicit) {
+ start_explicit = false;
+ release();
+ }
forceStop();
+ stopDependents();
+ stopped();
}
service_set->processQueues(false);
}
if (r > 0) {
// We read an errno code; exec() failed, and the service startup failed.
+ if (sr->pid != -1) {
+ sr->child_listener.deregister(eventLoop, sr->pid);
+ }
sr->pid = -1;
log(LogLevel::ERROR, sr->service_name, ": execution failed: ", strerror(exec_status));
if (sr->service_state == ServiceState::STARTING) {
waiting_for_deps = false;
+ // We overload can_interrupt_start to check whether there is any other
+ // process (eg restart timer) that needs to finish before starting.
+ if (can_interrupt_start()) {
+ waiting_for_deps = true;
+ return;
+ }
+
if (! open_socket()) {
failed_to_start();
}
kill(pid, term_signal);
}
- // In most cases, the rest is done in process_child_callback.
+ // In most cases, the rest is done in handle_exit_status.
// If we are a BGPROCESS and the process is not our immediate child, however, that
// won't work - check for this now:
if (service_type == ServiceType::BGPROCESS) {
{
restarting = false;
waiting_restart_timer = false;
+ restart_interval_count++;
// We may be STARTING (regular restart) or STARTED ("smooth recovery"). This affects whether
// the process should be granted access to the console:
// Check whether we're still in the most recent restart check interval:
timespec int_diff = diff_time(current_time, restart_interval_time);
if (int_diff < restart_interval) {
- if (++restart_interval_count >= max_restart_interval_count) {
+ if (restart_interval_count >= max_restart_interval_count) {
log(LogLevel::ERROR, "Service ", service_name, " restarting too quickly; stopping.");
return false;
}
protected:
+ // stop immediately
+ void emergency_stop() noexcept;
+
// All dependents have stopped.
virtual void all_deps_stopped() noexcept;
void run_child_proc(const char * const *args, const char *logfile, bool on_console, int wpipefd,
int csfd) noexcept;
- // Callback from libev when a child process dies
- static void process_child_callback(EventLoop_t *loop, ServiceChildWatcher *w,
- int revents) noexcept;
-
- //virtual void handle_exit_status(int exit_status) noexcept;
-
// A dependency has reached STARTED state
void dependencyStarted() noexcept;