Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
123 lines (93 sloc) 4.48 KB
What is init?
Or in particular, what is the minimal features an application must have
to action as process 1. This is an important question when it comes to
minimalistic init implementations.
The answer is this:
0. staying resident (not dying)
1. (re)spawning child process/es
2. reaping orphan zombies
These features follow from process spawning rules, and the special role
init (pid 1) has in the kernel:
A. all processes except init must have a parent process
B. init is the only one started by kernel
C. init can not die
D. orphans are re-assigned to init
Two more statements are assumed to be true to warrant using rather
complex unix-style system in the first place:
E. init should never be the only process running
for any arbitrary large time interval past boot
F. any non-init process is allowed to die
Indeed, with #A-#F considered,
#0 follows immediately from #C
#2 follows from #F + #D + #A
#1 follows from #E + #F + #A + #B
Init clusters
Features #1 and #2 for pid 1 can be replaced with weaker ones
by introducing additional process(es) not allowed to die,
in a form of uninterrupted lineage starting from init.
The result can be called an "init cluster".
Well-known example is the minimun init, found for example here:
In this example, #1 is replaced by
#1a. spawns a single child process not allowed to die
with the child process satisfying
#0. not allowed to die, and
#1. (re)spawning child processes
This way, pid 1 retains orphan-reaping function but delegates
respawning to the child process.
In a similar vein, it is possible to delegate orphan-reaping function
to a child process using prctl(PR_SET_CHILD_SUBREAPER).
The key point to note is that pid 1 in this example is incomplete
as far as init functions are concerted, and it's only the whole two-process
cluster that effectively implements #0, #1 and #2 features under
#A-#F conditions.
Splitting init into two processes only changes its internal structure,
and does not affect its functions.
Hybrid solutions
In the above sinit.c example, all children were delegated to a sub-init
process. Complete delegation is not mandatory however, it is possible
to have several sub-init processes each tending to its own children.
It is also quite possible to make a hierarchy, allowing non-dying sub-init
control a (possibly dying) respawner process which in turn would control
(possibly dying) children.
[init] <-- non-dying
+- [sub-init] <-- non-dying, respawns child
+- respawner <-- dying, respawns children
+- child1
+- child2
+- ...
And since pretty much any init implementation with full #1 (respawning) support
can act as either sub-init or respawner, it is possible to nest inits.
Nesting has been widely used to extend less-capable top-level init
with a more capable respawner, without replacing the top-level init.
Examples: sysvinit+initscripts, sysvinit+runit, sinit.c+runit,
suckless init (sinit + shell scripts).
Of particular note here is sysvinit+initscripts bundle, which extends
quite capable sysvinit with what does not even qualify as a respawner.
Does separating respawner from init make sense?
No. Any viable respawning init will by necessity act as a reaper.
This is because respawner needs to call waitpid(-1, ...) at some point
to keep track of dying children it must restart, and kernel makes sure
any orphan child will show up in init's waitpid results.
Only if waitpid gets called with something other than -1 for pid does
the above point fail. Doing that, however, hardly makes sense in an init.
Moving reaping duties into a separate process is pointless.
Writing complete init is not that difficult, and for generic systems
(with #E and #F in place) there is little sense in going with anything
less capable.
Does nesting inits make sense?
Yes, it does, barely, and only if done in a very specific way.
Running a complex respawner under supervision of a simple one
adds a kind of protection against kernel panic in case the complex
respawner dies.
The assumption is that the simple respawner (say, a non-configurable
mini-init only capable of restarting a single hard-coded command)
is much more stable than a complete init, and that if the complete init
fails, the mini-init will restart it.
Whether or not restarting init is any better than a full system reboot
after a kernel panic is an open question.