2 #include "proc-service.h"
4 // This is a mock implementation of the base_process_service class, for testing purposes.
6 base_process_service::base_process_service(service_set *sset, string name,
7 service_type_t service_type_p, string &&command,
8 std::list<std::pair<unsigned,unsigned>> &command_offsets,
9 const std::list<prelim_dep> &deplist_p)
10 : service_record(sset, name, service_type_p, deplist_p), child_listener(this),
11 child_status_listener(this), restart_timer(this)
13 program_name = std::move(command);
14 exec_arg_parts = separate_args(program_name, command_offsets);
16 restart_interval_count = 0;
17 restart_interval_time = {0, 0};
18 restart_timer.service = this;
19 //restart_timer.add_timer(event_loop);
21 // By default, allow a maximum of 3 restarts within 10.0 seconds:
22 restart_interval.seconds() = 10;
23 restart_interval.nseconds() = 0;
24 max_restart_interval_count = 3;
26 waiting_restart_timer = false;
27 reserved_child_watch = false;
28 tracking_child = false;
29 stop_timer_armed = false;
30 start_is_interruptible = false;
33 bool base_process_service::bring_up() noexcept
37 return restart_ps_process();
42 //event_loop.get_time(restart_interval_time, clock_type::MONOTONIC);
43 restart_interval_count = 0;
44 if (start_ps_process(exec_arg_parts, onstart_flags.starts_on_console)) {
45 if (start_timeout != time_val(0,0)) {
46 //restart_timer.arm_timer_rel(event_loop, start_timeout);
47 stop_timer_armed = true;
49 else if (stop_timer_armed) {
50 //restart_timer.stop_timer(event_loop);
51 stop_timer_armed = false;
59 void base_process_service::bring_down() noexcept
61 waiting_for_deps = false;
63 // The process is still kicking on - must actually kill it. We signal the process
64 // group (-pid) rather than just the process as there's less risk then of creating
65 // an orphaned process group:
66 if (! onstart_flags.no_sigterm) {
69 if (term_signal != -1) {
70 //kill_pg(term_signal);
73 // In most cases, the rest is done in handle_exit_status.
74 // If we are a BGPROCESS and the process is not our immediate child, however, that
75 // won't work - check for this now:
76 if (get_type() == service_type_t::BGPROCESS && ! tracking_child) {
79 else if (stop_timeout != time_val(0,0)) {
80 //restart_timer.arm_timer_rel(event_loop, stop_timeout);
81 stop_timer_armed = true;
85 // The process is already dead.
90 void base_process_service::do_smooth_recovery() noexcept
92 if (! restart_ps_process()) {
94 services->process_queues();
98 bool base_process_service::start_ps_process(const std::vector<const char *> &cmd, bool on_console) noexcept
103 void base_process_service::kill_with_fire() noexcept
106 //log(loglevel_t::WARN, "Service ", get_name(), " with pid ", pid, " exceeded allowed stop time; killing.");
111 void base_process_service::kill_pg(int signo) noexcept
113 //pid_t pgid = getpgid(pid);
115 // only should happen if pid is invalid, which should never happen...
116 //log(loglevel_t::ERROR, get_name(), ": can't signal process: ", strerror(errno));
119 //kill(-pgid, signo);
122 bool base_process_service::restart_ps_process() noexcept
124 using time_val = dasynq::time_val;
126 time_val current_time;
127 event_loop.get_time(current_time, clock_type::MONOTONIC);
129 if (max_restart_interval_count != 0) {
130 // Check whether we're still in the most recent restart check interval:
131 time_val int_diff = current_time - restart_interval_time;
132 if (int_diff < restart_interval) {
133 if (restart_interval_count >= max_restart_interval_count) {
134 //log(loglevel_t::ERROR, "Service ", get_name(), " restarting too quickly; stopping.");
139 restart_interval_time = current_time;
140 restart_interval_count = 0;
144 // Check if enough time has lapsed since the prevous restart. If not, start a timer:
145 time_val tdiff = current_time - last_start_time;
146 if (restart_delay <= tdiff) {
147 // > restart delay (normally 200ms)
151 time_val timeout = restart_delay - tdiff;
152 //restart_timer.arm_timer_rel(event_loop, timeout);
153 waiting_restart_timer = true;
158 void base_process_service::do_restart() noexcept
160 waiting_restart_timer = false;
161 restart_interval_count++;
162 auto service_state = get_state();
164 // We may be STARTING (regular restart) or STARTED ("smooth recovery"). This affects whether
165 // the process should be granted access to the console:
166 bool on_console = service_state == service_state_t::STARTING
167 ? onstart_flags.starts_on_console : onstart_flags.runs_on_console;
169 if (service_state == service_state_t::STARTING) {
170 // for a smooth recovery, we want to check dependencies are available before actually
172 if (! check_deps_started()) {
173 waiting_for_deps = true;
178 if (! start_ps_process(exec_arg_parts, on_console)) {
180 if (service_state == service_state_t::STARTING) {
184 // desired_state = service_state_t::STOPPED;
187 services->process_queues();
191 bool base_process_service::interrupt_start() noexcept
193 if (waiting_restart_timer) {
194 //restart_timer.stop_timer(event_loop);
195 waiting_restart_timer = false;
196 return service_record::interrupt_start();
199 //log(loglevel_t::WARN, "Interrupting start of service ", get_name(), " with pid ", pid, " (with SIGINT).");
201 if (stop_timeout != time_val(0,0)) {
202 restart_timer.arm_timer_rel(event_loop, stop_timeout);
203 stop_timer_armed = true;
205 else if (stop_timer_armed) {
206 restart_timer.stop_timer(event_loop);
207 stop_timer_armed = false;
209 set_state(service_state_t::STOPPING);
210 notify_listeners(service_event_t::STARTCANCELLED);
215 void base_process_service::timer_expired() noexcept
217 stop_timer_armed = false;
220 // We are stopping, including after having startup cancelled (stop timeout, state is STOPPING); We are
221 // starting (start timeout, state is STARTING); We are waiting for restart timer before restarting,
222 // including smooth recovery (restart timeout, state is STARTING or STARTED).
223 if (get_state() == service_state_t::STOPPING) {
226 else if (pid != -1) {
227 // Starting, start timed out.
232 // STARTING / STARTED, and we have a pid: must be restarting (smooth recovery if STARTED)