Faster booting with Upstart
by Mirko Dölle
A good portion of the boot time on current Linux systems is spent on system initialisation and starting dozens of daemons sequentially. The Ubuntu 9.10 development team have started to parallelise and accelerate the boot process through the large scale use of Upstart.
This article originally appeared in c't magazine 9/09, p. 176
Loading the Linux kernel takes up just a fraction of the time spent waiting for the login prompt during booting. The system spends most of its time sitting waiting for init
(which has its origins in Unix System V) to cycle through the various runlevels, during which it runs innumerable sequences of init scripts. In Ubuntu and Fedora, Upstart has long replaced the traditional SysV init.
The current boot sequence, with services starting consecutively in a fixed sequence, remains unaltered simply because no-one has sat down and adapted the init scripts for these various services to the capabilities of Upstart. Upstart simply emulates the SysV init runlevels (which actually no longer exist on systems running Upstart) and continues to call the old init scripts. For Ubuntu 9.10, the development team have finally started to convert some services to Upstart.
Both Upstart and SysV init are the first processes to be launched by the kernel (with ID 1) as soon as the latter has booted and any boot scripts from the initial ramdisk (initrd) have been run. For SysV init, the lynchpin of system initialisation is the /etc/inittab file. This is where SysV init finds the default runlevel, the name of the first initialisation script and the commands for initialising each runlevel. During runlevel initialisation, the linked init scripts in the relevant runlevel directory (e.g. /etc/rc5.d) are run sequentially.
For this to work, all services must run in the background as daemons and decouple themselves from the console, since the init script would otherwise hang until the service had terminated. This decoupling means that for init to determine whether a service is still running, or has self-terminated, is time-consuming. It generally achieves this by the daemon saving a file containing its process ID (PID) in /var/run, leaving it to the init script to determine whether a particular PID belongs to the daemon in question. One of the final init scripts launches the GUI. Once SysV init has run all of its scripts, services listed in the /etc/inittab file, such as login consoles, are then launched and monitored.
Upstart, by contrast, is event-oriented and works using 'jobs', with each job file in the /etc/init directory being responsible for launching a service or for a specific component of system initialisation. There is no fixed sequence; instead each job specifies the events to which it will react. When an event occurs, Upstart starts all jobs that have been waiting for this event, in parallel.
Upstart generates the first event, startup
, automatically when it is called. Each job also generates a started Jobname
and stopped Jobname
event on starting and terminating respectively. Various jobs take an interest in the startup
event in Ubuntu 9.10, including hostname
, which sets up the computer name. The associated job file is /etc/init/hostname.conf. The following example shows a very simplified version of this job:
start on startup
task
exec hostname -b -F /etc/hostname
The keyword start on
specifies the event which will trigger this job. If the job is to be triggered by multiple events, these events must be logically linked.
start on (runlevel [016]
and (stopped gdm
or stopped kdm
or stopped xdm))
Unlike in Ubuntu 9.04, there can no longer be multiple start on
lines. If the job subsequently needs to be terminated, stop on
is used to define additional stop events which in turn cause the job to be stopped.
If a job needs to be started or stopped manually, this can be achieved using
initctl start Jobname
and
initctl stop Jobname
.
The name of the program which the job should run follows the keyword exec
. One major difference between Upstart and SysV init is that services always run in the background in init scripts, since they would otherwise cause init to hang. Upstart, by contrast, expects the process following the exec
statement to run in the foreground, since Upstart only considers the job to be running for as long as this process is running. If a process started using exec
ends, Upstart considers the job to have ended and waits for another suitable event to occur (waiting). Upstart notes the status of each job listed in /etc/init. This information can be viewed using the initctl list
and initctl status Jobname
commands.