6.2 Transitions
Every transition peinit performs. Anything not listed here is not performed.
| From | To | Trigger |
|---|---|---|
| Inactive | Starting | Start command, dependency resolution, or a timer trigger. |
| Inactive | Skipped | A condition check failed. |
| Inactive | Failed | Validation, assertion, cycle or dependency failure — before any process existed. |
| Starting | Active | Readiness. Simple only: READY=1 received, or the process exists under Readiness=Alive. |
| Starting | Completed | Oneshot exited successfully. Without RemainAfterExit it passes through, releasing dependents, then goes Inactive. |
| Starting | Skipped | A condition failed after the activation had already entered Starting. |
| Starting | Failed | An assert failed after entering Starting; or a timeout, hook failure, setup failure, or an exit before readiness. |
| Starting | Backoff | A startup failure with the restart policy allowing a retry and budget remaining. |
| Starting | Stopping | An explicit stop cancelling an in-progress start. A restart on a Starting service is queued rather than cancelling. |
| Starting | Failed | The shutdown wave SIGKILLed a starting service. |
| Active | Reloading | ExecReload issued, or SIGHUP delivered. |
| Active | Stopping | Explicit stop, conflict eviction, a bound dependency stopping, or shutdown. |
| Active | Backoff | A crash, a watchdog timeout, or health check failure, with a restart allowed and budget remaining. |
| Active | Failed | The same three, with RestartPolicy=Never or the budget exhausted. |
| Active | Inactive | A Simple service exited successfully and RestartPolicy is not Always. Cause CleanExit. |
| Active | Backoff | A Simple service exited successfully and RestartPolicy=Always. Cause CleanExitRestart. |
| Reloading | Active | Reload resolved: READY=1, the detection window expiring, the extended wait expiring, or the reload command exiting — success or failure. |
| Reloading | Stopping | The same triggers as Active to Stopping. The reload is cancelled. |
| Reloading | Backoff | The main process exited during the reload, with a restart allowed. |
| Reloading | Failed | The same, with no restart available. |
| Stopping | Inactive | The process exited after an explicit stop or a shutdown. |
| Stopping | Failed | The process exited after a conflict eviction or a bound dependency stopping. |
| Stopping | Abandoned | SIGKILL sent and main/ still populated after the post-kill deadline. |
| Stopping | Starting | An explicit start queued against a service that is still stopping. Cause ExplicitStart. |
| Backoff | Starting | The backoff delay elapsed. Cause RestartPolicy. |
| Backoff | Inactive | An explicit stop cancelled the pending restart. |
| Backoff | Skipped | The backoff delay elapsed and the relaunch's pre-start checks skipped the service: its terminal is now held (§11.6), or a condition no longer holds. |
| Backoff | Failed | The backoff delay elapsed and peinit could not execute the relaunch. Cause InternalError. |
| Starting, Active, Reloading, Stopping | Failed | peinit could not carry out a step on the service and contained the error to it (§8.2). Cause InternalError. |
| Completed | Inactive | RemainAfterExit=0 and dependents released; or an explicit stop; or shutdown clearing it. |
| Completed | Starting | A start command or timer trigger re-running the Oneshot. |
| Failed | Starting | An explicit start, a bound dependency recovering, or a timer trigger. |
| Failed | Inactive | A reset command clearing the state. |
| Failed | Abandoned | A service SIGKILLed by the shutdown wave whose cgroup stayed populated past the post-kill deadline. |
| Abandoned | Inactive | A reset command. |
| Skipped | Inactive | A reset command, or an explicit start clearing Skipped before it re-evaluates the conditions. |
6.2.1 Things the table settles #
A restart never passes through Failed. A restart-eligible failure
goes to Backoff, waits, and goes to Starting.
Failed is reached only
when there will be no retry: RestartPolicy=Never, an invalid policy
for the cause, or an exhausted budget. This is why OnFailure (§6.3),
which fires on entry to Failed, does not fire on each retry — only when
the service finally fails out.
A clean exit is not a crash. A Simple service exiting zero goes to
Inactive under cause CleanExit, consulting neither the restart policy
nor the budget.
It goes to Backoff only under RestartPolicy=Always,
and then with the distinct cause CleanExitRestart, so status and
events say plainly that the process succeeded and was restarted by
policy rather than that anything went wrong.
A forced stop remembers why. Stopping to Failed carries the cause
from the transition that started the stop — ConflictEviction or
BindsToPropagation — rather than a generic failure.
A
service that lost a conflict and a service whose binding target went
away are distinguishable afterwards, which is what makes
bound-dependency recovery (§7.1) possible at all.
A restart detours through Inactive. The stop leg of an administrator's restart ends in Inactive, and the start leg begins from there. The two legs meet within one turn of the event loop, and peinit answers no request mid-turn, so no query ever sees the service Inactive in between.
A crash before readiness may be retried. A Simple process that exits
before signalling readiness is a ProcessCrash from Starting, and is
restart-eligible like any other, rather than a terminal startup failure.
A process can outlive its service's state. Most states are reached by the main process exiting, but not all of them: a watchdog timeout, a health check escalation and the post-kill give-up all move a service on while its process is still running. The exit that follows arrives for a service in Backoff, Abandoned or another state that no longer expects one.
peinit records that exit and performs no transition. The service keeps the state it had, any pending restart deadline stands, and the console reports it:
peinit: service <service> main process exited in state <state>; no action taken
This is deliberately not a fatal condition. A supervised service producing an unexpected sequence costs that service; it does not cost the machine. Treating it as a broken invariant of the runtime loop meant one crash-looping service dropped PID 1 into recovery mode and killed every session on the box.
6.2.2 Reset from Abandoned #
Resetting an Abandoned service re-checks its main/ sub-cgroup. If it
has finally emptied, peinit cleans up the whole service tree — main/,
hooks/, health/, then the root — and transitions to Inactive.
If it is still populated, peinit leaves the cgroup leaked, transitions to Inactive anyway, and returns this warning in the operation acknowledgement:
abandoned main cgroup for service <service> is still populated after
reset -- cgroup remains leaked; underlying D-state process requires
investigation
The warning is also written to the console, so a reset issued without reading the response still leaves a trace of the still-leaked cgroup.
The re-check targets main/. Note that the two paths into Abandoned
probe different cgroups: an explicit stop checks main/, while the
shutdown wave checks the service root.