在Ubuntu,Fedora,Debian发行版中,启动方式已由传统的sysvinit方式变为UpStart方式。UpStart相对于sysvinit启动方式有以下优点:
- 更快地启动系统(少启动了一些在开机时不必要的服务)
- 当新硬件被发现时动态启动服务(基于事件)
- 硬件被拔除时动态停止服务
UpStart简介
UpStart中有两个基本的概念:
job:一个工作的单元,用来执行一个任务或者服务,可以理解为一个服务脚本。
job分为以下三种:
- task job :一般的作业,用来完成一个特定的功能
- service job :服务进程,一般使用init来进行管理
- abstract job :upstart内部使用
job可能的状态如下:
状态名 | 含义 |
---|---|
Waiting | 初始状态 |
Starting | Job 即将开始 |
pre-start | 执行 pre-start 段,即任务开始前应该完成的工作 |
Spawned | 准备执行 script 或者 exec 段 |
post-start | 执行 post-start 动作 |
Running | interim state set after post-start section processed denoting job is running (But it may have no associated PID!) |
pre-stop | 执行 pre-stop 段 |
Stopping | interim state set after pre-stop section processed |
Killed | 任务即将被停止 |
post-stop | 执行 post-stop 段 |
其中有四个状态会引起 init 进程发送相应的事件,表明该工作的相应变化:
- Starting
- Started
- Stopping
- Stopped
而其它的状态变化不会发出事件。
event:事件,事件在UpStart中以通知消息的形式具体存在,一旦某个事件发生了,UpStart就向系统发送一条消息。
UpStart是一个由事件触发工作执行的系统,每一个工作的执行都由其依赖的事情的发生而触发。系统服务的启动和终止都是由事件决定的。
事件可以分为三类:
- signals :异步非阻塞的,发送之后立即返回。
- methods :同步阻塞的。
- hooks :同步阻塞
UpStart的启动过程:
系统时如何知道自己什么时候启动,什么时候终止的呢?答案就在/etc/init中,该目录下均是系统服务的配置文件。
实际上
并不仅仅在系统启动初期,在系统运转的任何时期都可以通过发送事件来启动或终止服务
。UpStart启动方式实现了对sysvinit方式的兼容,顺序和sysvinit基本一致,只不过是通过事件驱动的,最后的执行脚本在/etc/init(upstart的工作配置文件job configuration file)和/etc/init.d(sysvinit方式的启动脚本)目录下。具体两种不同启动方式的脚本的书写方式不一致,可以参考sysvinit启动脚本和upstart启动脚本的编写。
图中的红色箭头是事件。
上图中,在内核初始化的最后阶段启动init进程。然后upstart自身进行一些初始化工作之后发出startup事件。
下图是/etc/rc-sysinit.conf文件的内容
(注意的是在upstart中服务的名字和配置文件同名,如rc-sysinit.conf的服务名称就是rc-sysinit)
# rc-sysinit - System V initialisation compatibility
#
# This task runs the old System V-style system initialisation scripts,
# and enters the default runlevel when finished.
description "System V initialisation compatibility"
author "Scott James Remnant <scott@netsplit.com>" #这两条命令是upstart工作配置文件中特有的stanza(节)
start on filesystem and net-device-up IFACE=lo #当filesystem和net-device-up IFACE=lo事件同时发生时启动这个服务
stop on runlevel
# Default runlevel, this may be overriden on the kernel command-line
# or by faking an old /etc/inittab entry
env DEFAULT_RUNLEVEL=2
task
#
# This task runs the old System V-style system initialisation scripts,
# and enters the default runlevel when finished.
description "System V initialisation compatibility"
author "Scott James Remnant <scott@netsplit.com>" #这两条命令是upstart工作配置文件中特有的stanza(节)
start on filesystem and net-device-up IFACE=lo #当filesystem和net-device-up IFACE=lo事件同时发生时启动这个服务
stop on runlevel
# Default runlevel, this may be overriden on the kernel command-line
# or by faking an old /etc/inittab entry
env DEFAULT_RUNLEVEL=2
task
script
# Check for default runlevel in /etc/inittab
if [ -r /etc/inittab ]
then
eval "$(sed -nre 's/^[^#][^:]*:([0-6sS]):initdefault:.*/DEFAULT_RUNLEVEL="\1";/p' /etc/inittab || true)"
fi
# Check kernel command-line for typical arguments
for ARG in $(cat /proc/cmdline)
do
case "${ARG}" in
-b|emergency)
# Emergency shell
[ -n "${FROM_SINGLE_USER_MODE}" ] || sulogin
;;
[0123456sS])
# Override runlevel
DEFAULT_RUNLEVEL="${ARG}"
;;
-s|single)
# Single user mode
[ -n "${FROM_SINGLE_USER_MODE}" ] || DEFAULT_RUNLEVEL=S
;;
esac
done
# Check for default runlevel in /etc/inittab
if [ -r /etc/inittab ]
then
eval "$(sed -nre 's/^[^#][^:]*:([0-6sS]):initdefault:.*/DEFAULT_RUNLEVEL="\1";/p' /etc/inittab || true)"
fi
# Check kernel command-line for typical arguments
for ARG in $(cat /proc/cmdline)
do
case "${ARG}" in
-b|emergency)
# Emergency shell
[ -n "${FROM_SINGLE_USER_MODE}" ] || sulogin
;;
[0123456sS])
# Override runlevel
DEFAULT_RUNLEVEL="${ARG}"
;;
-s|single)
# Single user mode
[ -n "${FROM_SINGLE_USER_MODE}" ] || DEFAULT_RUNLEVEL=S
;;
esac
done
# Run the system initialisation scripts
[ -n "${FROM_SINGLE_USER_MODE}" ] || /etc/init.d/rcS
# Switch into the default runlevel
telinit "${DEFAULT_RUNLEVEL}"
end script
[ -n "${FROM_SINGLE_USER_MODE}" ] || /etc/init.d/rcS
# Switch into the default runlevel
telinit "${DEFAULT_RUNLEVEL}"
end script
最后一句telinit+DEFAULT_RUNLEVEL立即产生runlevel改变的事件,此时rc服务启动,执行rc.conf文件。
# rc - System V runlevel compatibility
#
# This task runs the old System V-style rc script when changing between
# runlevels.
description "System V runlevel compatibility"
author "Scott James Remnant <scott@netsplit.com>"
start on runlevel [0123456] #任何时候runlevel的改变都会执行rc工作
stop on runlevel [!$RUNLEVEL]
export RUNLEVEL
export PREVLEVEL
console output
env INIT_VERBOSE
task
exec /etc/init.d/rc $RUNLEVEL
#
# This task runs the old System V-style rc script when changing between
# runlevels.
description "System V runlevel compatibility"
author "Scott James Remnant <scott@netsplit.com>"
start on runlevel [0123456] #任何时候runlevel的改变都会执行rc工作
stop on runlevel [!$RUNLEVEL]
export RUNLEVEL
export PREVLEVEL
console output
env INIT_VERBOSE
task
exec /etc/init.d/rc $RUNLEVEL
最后一条命令通过调用rc服务执行rcX.d/下面的工作。
整体 Init
启动总结: