5 #include "dinit-socket.h"
6 #include "proc-service.h"
8 #include "baseproc-sys.h"
11 * Base process implementation (base_process_service).
13 * See proc-service.h for interface documentation.
16 void base_process_service::do_smooth_recovery() noexcept
18 if (! restart_ps_process()) {
20 services->process_queues();
24 bool base_process_service::bring_up() noexcept
28 return restart_ps_process();
33 event_loop.get_time(restart_interval_time, clock_type::MONOTONIC);
34 restart_interval_count = 0;
35 if (start_ps_process(exec_arg_parts, onstart_flags.starts_on_console)) {
36 if (start_timeout != time_val(0,0)) {
37 restart_timer.arm_timer_rel(event_loop, start_timeout);
38 stop_timer_armed = true;
40 else if (stop_timer_armed) {
41 restart_timer.stop_timer(event_loop);
42 stop_timer_armed = false;
50 bool base_process_service::start_ps_process(const std::vector<const char *> &cmd, bool on_console) noexcept
52 // In general, you can't tell whether fork/exec is successful. We use a pipe to communicate
53 // success/failure from the child to the parent. The pipe is set CLOEXEC so a successful
54 // exec closes the pipe, and the parent sees EOF. If the exec is unsuccessful, the errno
55 // is written to the pipe, and the parent can read it.
57 event_loop.get_time(last_start_time, clock_type::MONOTONIC);
60 if (bp_sys::pipe2(pipefd, O_CLOEXEC)) {
61 log(loglevel_t::ERROR, get_name(), ": can't create status check pipe: ", strerror(errno));
65 const char * logfile = this->logfile.c_str();
67 logfile = "/dev/null";
70 bool child_status_registered = false;
71 control_conn_t *control_conn = nullptr;
73 int control_socket[2] = {-1, -1};
74 if (onstart_flags.pass_cs_fd) {
75 if (dinit_socketpair(AF_UNIX, SOCK_STREAM, /* protocol */ 0, control_socket, SOCK_NONBLOCK)) {
76 log(loglevel_t::ERROR, get_name(), ": can't create control socket: ", strerror(errno));
80 // Make the server side socket close-on-exec:
81 int fdflags = bp_sys::fcntl(control_socket[0], F_GETFD);
82 bp_sys::fcntl(control_socket[0], F_SETFD, fdflags | FD_CLOEXEC);
85 control_conn = new control_conn_t(event_loop, services, control_socket[0]);
87 catch (std::exception &exc) {
88 log(loglevel_t::ERROR, get_name(), ": can't launch process; out of memory");
93 // Set up complete, now fork and exec:
98 child_status_listener.add_watch(event_loop, pipefd[0], dasynq::IN_EVENTS);
99 child_status_registered = true;
101 // We specify a high priority (i.e. low priority value) so that process termination is
102 // handled early. This means we have always recorded that the process is terminated by the
103 // time that we handle events that might otherwise cause us to signal the process, so we
104 // avoid sending a signal to an invalid (and possibly recycled) process ID.
105 forkpid = child_listener.fork(event_loop, reserved_child_watch, dasynq::DEFAULT_PRIORITY - 10);
106 reserved_child_watch = true;
108 catch (std::exception &e) {
109 log(loglevel_t::ERROR, get_name(), ": Could not fork: ", e.what());
114 run_child_proc(cmd.data(), logfile, on_console, pipefd[1], control_socket[1]);
118 bp_sys::close(pipefd[1]); // close the 'other end' fd
119 if (control_socket[1] != -1) {
120 bp_sys::close(control_socket[1]);
124 waiting_for_execstat = true;
131 if (child_status_registered) {
132 child_status_listener.deregister(event_loop);
135 if (onstart_flags.pass_cs_fd) {
139 bp_sys::close(control_socket[0]);
140 bp_sys::close(control_socket[1]);
144 bp_sys::close(pipefd[0]);
145 bp_sys::close(pipefd[1]);
150 void base_process_service::bring_down() noexcept
152 waiting_for_deps = false;
154 // The process is still kicking on - must actually kill it. We signal the process
155 // group (-pid) rather than just the process as there's less risk then of creating
156 // an orphaned process group:
157 if (! onstart_flags.no_sigterm) {
160 if (term_signal != -1) {
161 kill_pg(term_signal);
164 // In most cases, the rest is done in handle_exit_status.
165 // If we are a BGPROCESS and the process is not our immediate child, however, that
166 // won't work - check for this now:
167 if (get_type() == service_type_t::BGPROCESS && ! tracking_child) {
170 else if (stop_timeout != time_val(0,0)) {
171 restart_timer.arm_timer_rel(event_loop, stop_timeout);
172 stop_timer_armed = true;
176 // The process is already dead.
181 base_process_service::base_process_service(service_set *sset, string name,
182 service_type_t service_type_p, string &&command,
183 std::list<std::pair<unsigned,unsigned>> &command_offsets,
184 const std::list<prelim_dep> &deplist_p)
185 : service_record(sset, name, service_type_p, deplist_p), child_listener(this),
186 child_status_listener(this), restart_timer(this)
188 program_name = std::move(command);
189 exec_arg_parts = separate_args(program_name, command_offsets);
191 restart_interval_count = 0;
192 restart_interval_time = {0, 0};
193 restart_timer.service = this;
194 restart_timer.add_timer(event_loop);
196 // By default, allow a maximum of 3 restarts within 10.0 seconds:
197 restart_interval.seconds() = 10;
198 restart_interval.nseconds() = 0;
199 max_restart_interval_count = 3;
201 waiting_restart_timer = false;
202 reserved_child_watch = false;
203 tracking_child = false;
204 stop_timer_armed = false;
205 start_is_interruptible = false;
208 void base_process_service::do_restart() noexcept
210 waiting_restart_timer = false;
211 restart_interval_count++;
212 auto service_state = get_state();
214 // We may be STARTING (regular restart) or STARTED ("smooth recovery"). This affects whether
215 // the process should be granted access to the console:
216 bool on_console = service_state == service_state_t::STARTING
217 ? onstart_flags.starts_on_console : onstart_flags.runs_on_console;
219 if (service_state == service_state_t::STARTING) {
220 // for a smooth recovery, we want to check dependencies are available before actually
222 if (! check_deps_started()) {
223 waiting_for_deps = true;
228 if (! start_ps_process(exec_arg_parts, on_console)) {
230 if (service_state == service_state_t::STARTING) {
234 // desired_state = service_state_t::STOPPED;
237 services->process_queues();
241 bool base_process_service::restart_ps_process() noexcept
243 using time_val = dasynq::time_val;
245 time_val current_time;
246 event_loop.get_time(current_time, clock_type::MONOTONIC);
248 if (max_restart_interval_count != 0) {
249 // Check whether we're still in the most recent restart check interval:
250 time_val int_diff = current_time - restart_interval_time;
251 if (int_diff < restart_interval) {
252 if (restart_interval_count >= max_restart_interval_count) {
253 log(loglevel_t::ERROR, "Service ", get_name(), " restarting too quickly; stopping.");
258 restart_interval_time = current_time;
259 restart_interval_count = 0;
263 // Check if enough time has lapsed since the prevous restart. If not, start a timer:
264 time_val tdiff = current_time - last_start_time;
265 if (restart_delay <= tdiff) {
266 // > restart delay (normally 200ms)
270 time_val timeout = restart_delay - tdiff;
271 restart_timer.arm_timer_rel(event_loop, timeout);
272 waiting_restart_timer = true;
277 bool base_process_service::interrupt_start() noexcept
279 if (waiting_restart_timer) {
280 restart_timer.stop_timer(event_loop);
281 waiting_restart_timer = false;
282 return service_record::interrupt_start();
285 log(loglevel_t::WARN, "Interrupting start of service ", get_name(), " with pid ", pid, " (with SIGINT).");
287 if (stop_timeout != time_val(0,0)) {
288 restart_timer.arm_timer_rel(event_loop, stop_timeout);
289 stop_timer_armed = true;
291 else if (stop_timer_armed) {
292 restart_timer.stop_timer(event_loop);
293 stop_timer_armed = false;
295 set_state(service_state_t::STOPPING);
296 notify_listeners(service_event_t::STARTCANCELLED);
301 void base_process_service::kill_with_fire() noexcept
304 log(loglevel_t::WARN, "Service ", get_name(), " with pid ", pid, " exceeded allowed stop time; killing.");
309 void base_process_service::kill_pg(int signo) noexcept
311 pid_t pgid = bp_sys::getpgid(pid);
313 // only should happen if pid is invalid, which should never happen...
314 log(loglevel_t::ERROR, get_name(), ": can't signal process: ", strerror(errno));
317 bp_sys::kill(-pgid, signo);
320 void base_process_service::timer_expired() noexcept
322 stop_timer_armed = false;
325 // We are stopping, including after having startup cancelled (stop timeout, state is STOPPING); We are
326 // starting (start timeout, state is STARTING); We are waiting for restart timer before restarting,
327 // including smooth recovery (restart timeout, state is STARTING or STARTED).
328 if (get_state() == service_state_t::STOPPING) {
331 else if (pid != -1) {
332 // Starting, start timed out.
334 if (start_explicit) {
335 start_explicit = false;
341 // STARTING / STARTED, and we have a pid: must be restarting (smooth recovery if STARTED)