13 #include "dinit-log.h"
14 #include "dinit-socket.h"
15 #include "dinit-util.h"
16 #include "baseproc-sys.h"
19 * service.cc - Service management.
20 * See service.h for details.
23 // Find the requested service by name
24 static service_record * find_service(const std::list<service_record *> & records,
25 const char *name) noexcept
28 list<service_record *>::const_iterator i = records.begin();
29 for ( ; i != records.end(); ++i ) {
30 if (strcmp((*i)->get_name().c_str(), name) == 0) {
37 service_record * service_set::find_service(const std::string &name) noexcept
39 return ::find_service(records, name.c_str());
42 // Called when a service has actually stopped; dependents have stopped already, unless this stop
43 // is due to an unexpected process termination.
44 void service_record::stopped() noexcept
47 bp_sys::tcsetpgrp(0, bp_sys::getpgrp());
53 restarting |= auto_restart;
54 bool will_restart = restarting && required_by > 0;
55 if (restarting && ! will_restart) {
56 notify_listeners(service_event_t::STARTCANCELLED);
60 // If we won't restart, break soft dependencies now
62 for (auto dept : dependents) {
63 if (! dept->is_hard()) {
64 // waits-for or soft dependency:
65 if (dept->waiting_on) {
66 dept->waiting_on = false;
67 dept->get_from()->dependency_started();
69 if (dept->holding_acq) {
70 dept->holding_acq = false;
71 // release without issuing stop, since we're called only when this
72 // service is already stopped/stopping:
79 for (auto & dependency : depends_on) {
80 // we signal dependencies in case they are waiting for us to stop:
81 dependency.get_to()->dependent_stopped();
84 service_state = service_state_t::STOPPED;
87 // Desired state is "started".
95 // If we were explicitly started, our required_by count must be at least 1. Use
96 // release() to correctly release, mark inactive and release dependencies.
97 start_explicit = false;
100 else if (required_by == 0) {
101 // This can only be the case if we didn't have start_explicit, since required_by would
102 // otherwise by non-zero.
103 prop_release = !prop_require;
104 prop_require = false;
105 services->add_prop_queue(this);
106 services->service_inactive(this);
110 // Start failure will have been logged already, only log if we are stopped for other reasons:
111 if (! start_failed) {
112 log_service_stopped(service_name);
114 // If this service chains to another, start the other service now:
115 if (! will_restart && ! start_on_completion.empty()) {
117 auto chain_to = services->load_service(start_on_completion.c_str());
120 catch (service_load_exc &sle) {
121 log(loglevel_t::ERROR, "Couldn't chain to service ", start_on_completion, ": ",
122 "couldn't load ", sle.service_name, ": ", sle.exc_description);
124 catch (std::bad_alloc &bae) {
125 log(loglevel_t::ERROR, "Couldn't chain to service ", start_on_completion,
130 notify_listeners(service_event_t::STOPPED);
133 void service_record::require() noexcept
135 if (required_by++ == 0) {
136 prop_require = !prop_release;
137 prop_release = false;
138 services->add_prop_queue(this);
139 if (service_state != service_state_t::STARTING && service_state != service_state_t::STARTED) {
145 void service_record::release(bool issue_stop) noexcept
147 if (--required_by == 0) {
148 desired_state = service_state_t::STOPPED;
149 prop_require = false;
151 // Can stop, and can release dependencies now. We don't need to issue a release if
152 // the require was pending though:
153 if (service_state != service_state_t::STOPPED && service_state != service_state_t::STOPPING) {
154 prop_release = !prop_require;
155 prop_require = false;
156 services->add_prop_queue(this);
159 if (service_state == service_state_t::STOPPED) {
160 services->service_inactive(this);
162 else if (issue_stop) {
163 stop_reason = stopped_reason_t::NORMAL;
169 void service_record::release_dependencies() noexcept
171 for (auto & dependency : depends_on) {
172 service_record * dep_to = dependency.get_to();
173 if (dependency.holding_acq) {
174 // We must clear holding_acq before calling release, otherwise the dependency
175 // may decide to stop, check this link and release itself a second time.
176 dependency.holding_acq = false;
182 void service_record::start(bool activate) noexcept
184 if (activate && ! start_explicit) {
186 start_explicit = true;
189 bool was_active = service_state != service_state_t::STOPPED || desired_state != service_state_t::STOPPED;
190 desired_state = service_state_t::STARTED;
192 if (service_state != service_state_t::STOPPED) {
193 // We're already starting/started, or we are stopping and need to wait for
194 // that the complete.
195 if (service_state != service_state_t::STOPPING) {
199 if (! can_interrupt_stop()) {
204 // We're STOPPING, and that can be interrupted. Our dependencies might be STOPPING,
205 // but if so they are waiting (for us), so they too can be instantly returned to
207 notify_listeners(service_event_t::STOPCANCELLED);
209 else if (! was_active) {
210 services->service_active(this);
213 start_failed = false;
214 start_skipped = false;
215 service_state = service_state_t::STARTING;
216 waiting_for_deps = true;
218 if (start_check_dependencies()) {
219 services->add_transition_queue(this);
223 void service_record::do_propagation() noexcept
226 // Need to require all our dependencies
227 for (auto & dep : depends_on) {
228 dep.get_to()->require();
229 dep.holding_acq = true;
231 prop_require = false;
235 release_dependencies();
236 prop_release = false;
240 prop_failure = false;
241 stop_reason = stopped_reason_t::DEPFAILED;
242 failed_to_start(true);
256 void service_record::execute_transition() noexcept
258 // state is STARTED with restarting set true if we are running a smooth recovery.
259 if (service_state == service_state_t::STARTING || (service_state == service_state_t::STARTED
261 if (check_deps_started()) {
265 else if (service_state == service_state_t::STOPPING) {
266 if (stop_check_dependents()) {
267 waiting_for_deps = false;
269 // A service that does actually stop for any reason should have its explicit activation released, unless
271 if (start_explicit && !auto_restart && !restarting) {
272 start_explicit = false;
281 void service_record::do_start() noexcept
283 if (pinned_stopped) return;
285 if (service_state != service_state_t::STARTING) {
289 service_state = service_state_t::STARTING;
291 waiting_for_deps = true;
293 // Ask dependencies to start, mark them as being waited on.
294 if (check_deps_started()) {
295 // Once all dependencies are started, we start properly:
300 void service_record::dependency_started() noexcept
302 // Note that we check for STARTED state here in case the service is in smooth recovery while pinned.
303 // In that case it will wait for dependencies to start before restarting the process.
304 if ((service_state == service_state_t::STARTING || service_state == service_state_t::STARTED)
305 && waiting_for_deps) {
306 services->add_transition_queue(this);
310 bool service_record::start_check_dependencies() noexcept
312 bool all_deps_started = true;
314 for (auto & dep : depends_on) {
315 service_record * to = dep.get_to();
316 if (to->service_state != service_state_t::STARTED) {
317 if (to->service_state != service_state_t::STARTING) {
318 to->prop_start = true;
319 services->add_prop_queue(to);
321 dep.waiting_on = true;
322 all_deps_started = false;
326 return all_deps_started;
329 bool service_record::check_deps_started() noexcept
331 for (auto & dep : depends_on) {
332 if (dep.waiting_on) {
340 void service_record::all_deps_started() noexcept
342 if (onstart_flags.starts_on_console && ! have_console) {
347 waiting_for_deps = false;
349 if (! can_proceed_to_start()) {
350 waiting_for_deps = true;
354 bool start_success = bring_up();
356 if (! start_success) {
361 void service_record::acquired_console() noexcept
363 waiting_for_console = false;
366 if (service_state != service_state_t::STARTING) {
367 // We got the console but no longer want it.
370 else if (check_deps_started()) {
374 // We got the console but can't use it yet.
379 void service_record::started() noexcept
381 // If we start on console but don't keep it, release it now:
382 if (have_console && ! onstart_flags.runs_on_console) {
383 bp_sys::tcsetpgrp(0, bp_sys::getpgrp());
387 log_service_started(get_name());
388 service_state = service_state_t::STARTED;
389 notify_listeners(service_event_t::STARTED);
391 if (onstart_flags.rw_ready) {
394 if (onstart_flags.log_ready) {
395 setup_external_log();
398 if (force_stop || desired_state == service_state_t::STOPPED) {
404 // Notify any dependents whose desired state is STARTED:
405 for (auto dept : dependents) {
406 dept->get_from()->dependency_started();
407 dept->waiting_on = false;
411 void service_record::failed_to_start(bool depfailed, bool immediate_stop) noexcept
413 if (waiting_for_console) {
414 services->unqueue_console(this);
415 waiting_for_console = false;
418 if (start_explicit) {
419 start_explicit = false;
423 // Cancel start of dependents:
424 for (auto & dept : dependents) {
425 switch (dept->dep_type) {
426 case dependency_type::REGULAR:
427 case dependency_type::MILESTONE:
428 if (dept->get_from()->service_state == service_state_t::STARTING) {
429 dept->get_from()->prop_failure = true;
430 services->add_prop_queue(dept->get_from());
433 case dependency_type::WAITS_FOR:
434 case dependency_type::SOFT:
435 if (dept->waiting_on) {
436 dept->waiting_on = false;
437 dept->get_from()->dependency_started();
441 // Always release now, so that our desired state will be STOPPED before we call
442 // stopped() below (if we do so). Otherwise it may decide to restart us.
443 if (dept->holding_acq) {
444 dept->holding_acq = false;
450 log_service_failed(get_name());
451 notify_listeners(service_event_t::FAILEDSTART);
453 if (immediate_stop) {
458 bool service_record::bring_up() noexcept
460 // default implementation: there is no process, so we are started.
465 // Mark this and all dependent services as force-stopped.
466 void service_record::forced_stop() noexcept
468 if (service_state != service_state_t::STOPPED) {
470 if (! pinned_started) {
472 services->add_prop_queue(this);
477 void service_record::dependent_stopped() noexcept
479 if (service_state == service_state_t::STOPPING && waiting_for_deps) {
480 services->add_transition_queue(this);
484 void service_record::stop(bool bring_down) noexcept
486 if (start_explicit) {
487 start_explicit = false;
491 // If our required_by count is 0, we should treat this as a full manual stop regardless
492 if (required_by == 0) {
496 desired_state = service_state_t::STOPPED;
498 if (bring_down && service_state != service_state_t::STOPPED
499 && service_state != service_state_t::STOPPING) {
500 stop_reason = stopped_reason_t::NORMAL;
505 bool service_record::restart() noexcept
507 // Re-start without affecting dependency links/activation.
509 if (service_state == service_state_t::STARTED) {
511 stop_reason = stopped_reason_t::NORMAL;
520 void service_record::do_stop() noexcept
522 // Called when we should definitely stop. We may need to restart afterwards, but we
523 // won't know that for sure until the execution transition.
525 bool all_deps_stopped = stop_dependents();
527 if (service_state != service_state_t::STARTED) {
528 if (service_state == service_state_t::STARTING) {
529 // If waiting for a dependency, or waiting for the console, we can interrupt start. Otherwise,
530 // we need to delegate to can_interrupt_start() (which can be overridden).
531 if (! waiting_for_deps && ! waiting_for_console) {
532 if (! can_interrupt_start()) {
533 // Well this is awkward: we're going to have to continue starting. We can stop once
534 // we've reached the started state.
538 if (! interrupt_start()) {
539 // Now wait for service startup to actually end; we don't need to handle it here.
540 notify_listeners(service_event_t::STARTCANCELLED);
544 else if (waiting_for_console) {
545 services->unqueue_console(this);
546 waiting_for_console = false;
549 // We must have had desired_state == STARTED.
550 notify_listeners(service_event_t::STARTCANCELLED);
552 // Reaching this point, we are starting interruptibly - so we
553 // stop now (by falling through to below).
556 // If we're starting we need to wait for that to complete.
557 // If we're already stopping/stopped there's nothing to do.
562 if (pinned_started) return;
564 service_state = service_state_t::STOPPING;
565 waiting_for_deps = true;
566 if (all_deps_stopped) {
567 services->add_transition_queue(this);
571 bool service_record::stop_check_dependents() noexcept
573 bool all_deps_stopped = true;
574 for (auto dept : dependents) {
575 if (dept->is_hard() && dept->holding_acq) {
576 all_deps_stopped = false;
581 return all_deps_stopped;
584 bool service_record::stop_dependents() noexcept
586 bool all_deps_stopped = true;
587 for (auto dept : dependents) {
588 if (dept->is_hard() && dept->holding_acq) {
589 if (! dept->get_from()->is_stopped()) {
590 // Note we check *first* since if the dependent service is not stopped,
591 // 1. We will issue a stop to it shortly and
592 // 2. It will notify us when stopped, at which point the stop_check_dependents()
593 // check is run anyway.
594 all_deps_stopped = false;
598 // If this service is to be forcefully stopped, dependents must also be.
599 dept->get_from()->forced_stop();
602 dept->get_from()->prop_stop = true;
603 services->add_prop_queue(dept->get_from());
605 // Note that soft dependencies are held (for now). If we restart, we don't want those dependencies
609 return all_deps_stopped;
612 // All dependents have stopped; we can stop now, too. Only called when STOPPING.
613 void service_record::bring_down() noexcept
615 waiting_for_deps = false;
619 void service_record::unpin() noexcept
621 if (pinned_started) {
622 pinned_started = false;
624 for (auto &dep : depends_on) {
626 if (dep.get_to()->get_state() != service_state_t::STARTED) {
627 desired_state = service_state_t::STOPPED;
630 else if (dep.holding_acq) {
631 dep.holding_acq = false;
632 dep.get_to()->release();
636 if (desired_state == service_state_t::STOPPED || force_stop) {
638 services->process_queues();
641 if (pinned_stopped) {
642 pinned_stopped = false;
643 if (desired_state == service_state_t::STARTED) {
645 services->process_queues();
650 void service_record::queue_for_console() noexcept
652 waiting_for_console = true;
653 services->append_console_queue(this);
656 void service_record::release_console() noexcept
658 have_console = false;
659 services->pull_console_queue();
662 bool service_record::interrupt_start() noexcept
667 void service_set::service_active(service_record *sr) noexcept
672 void service_set::service_inactive(service_record *sr) noexcept