浅析 Linux 初始化 init 系统,第 2 部分: UpStart(2)

顾名思义,Event 就是一个事件。事件在 upstart 中以通知消息的形式具体存在。一旦某个事件发生了,Upstart 就向整个系统发送一个消息。没有任何手段阻止事件消息被 upstart 的其它部分知晓,也就是说,事件一旦发生,整个 upstart 系统中所有工作和其它的事件都会得到通知。

Event 可以分为三类: signal,methods 或者 hooks。

Signals

Signal 事件是非阻塞的,异步的。发送一个信号之后控制权立即返回。

Methods

Methods 事件是阻塞的,同步的。

Hooks

Hooks 事件是阻塞的,同步的。它介于 Signals 和 Methods 之间,调用发出 Hooks 事件的进程必须等待事件完成才可以得到控制权,但不检查事件是否成功。

事件是个非常抽象的概念,下面我罗列出一些常见的事件,希望可以帮助您进一步了解事件的含义:

系统上电启动,init 进程会发送"start"事件

根文件系统可写时,相应 job 会发送文件系统就绪的事件

一个块设备被发现并初始化完成,发送相应的事件

某个文件系统被挂载,发送相应的事件

类似 atd 和 cron,可以在某个时间点,或者周期的时间点发送事件

另外一个 job 开始或结束时,发送相应的事件

一个磁盘文件被修改时,可以发出相应的事件

一个网络设备被发现时,可以发出相应的事件

缺省路由被添加或删除时,可以发出相应的事件

不同的 Linux 发行版对 upstart 有不同的定制和实现,实现和支持的事件也有所不同,可以用man 7 upstart-events来查看事件列表。

Job 和 Event 的相互协作

Upstart 就是由事件触发工作运行的一个系统,每一个程序的运行都由其依赖的事件发生而触发的。

系统初始化的过程是在工作和事件的相互协作下完成的,可以大致描述如下:系统初始化时,init 进程开始运行,init 进程自身会发出不同的事件,这些最初的事件会触发一些工作运行。每个工作运行过程中会释放不同的事件,这些事件又将触发新的工作运行。如此反复,直到整个系统正常运行起来。

究竟哪些事件会触发某个工作的运行?这是由工作配置文件定义的。

工作配置文件

任何一个工作都是由一个工作配置文件(Job Configuration File)定义的。这个文件是一个文本文件,包含一个或者多个小节(stanza)。每个小节是一个完整的定义模块,定义了工作的一个方面,比如 author 小节定义了工作的作者。工作配置文件存放在/etc/init 下面,是以.conf 作为文件后缀的文件。

清单 1. 一个最简单的工作配置文件

#This is a simple demo of Job Configure file

#This line is comment, start with #

 

#Stanza 1, The author

author LiuMing

 

#Stanza 2, Description

description This job only has author and description, so nouse, just a demo

上面的例子不会产生任何作用,一个真正的工作配置文件会包含很多小节,其中比较重要的小节有以下几个:

"expect" Stanza

Upstart 除了负责系统的启动过程之外,和 SysVinit 一样,Upstart 还提供一系列的管理工具。当系统启动之后,管理员可能还需要进行维护和调整,比如启动或者停止某项系统服务。或者将系统切换到其它的工作状态,比如改变运行级别。本文后续将详细介绍 Upstart 的管理工具的使用。

为了启动,停止,重启和查询某个系统服务。Upstart 需要跟踪该服务所对应的进程。比如 httpd 服务的进程 PID 为 1000。当用户需要查询 httpd 服务是否正常运行时,Upstart 就可以利用 ps 命令查询进程 1000,假如它还在正常运行,则表明服务正常。当用户需要停止 httpd 服务时,Upstart 就使用 kill 命令终止该进程。为此,Upstart 必须跟踪服务进程的进程号。

部分服务进程为了将自己变成后台精灵进程(daemon),会采用两次派生(fork)的技术,另外一些服务则不会这样做。假如一个服务派生了两次,那么 UpStart 必须采用第二个派生出来的进程号作为服务的 PID。但是,UpStart 本身无法判断服务进程是否会派生两次,为此在定义该服务的工作配置文件中必须写明 expect 小节,告诉 UpStart 进程是否会派生两次。

Expect 有两种,"expect fork"表示进程只会 fork 一次;"expect daemonize"表示进程会 fork 两次。

"exec" Stanza 和"script" Stanza

一个 UpStart 工作一定需要做些什么,可能是运行一条 shell 命令,或者运行一段脚本。用"exec"关键字配置工作需要运行的命令;用"script"关键字定义需要运行的脚本。

清单 2 显示了 exec 和 script 的用法:

清单 2.script 例子

# mountall.conf

description Mount filesystems on boot

start on startup

stop on starting rcS

...

script

./etc/default/rcS

[-f /forcefsck ]&& force_fsck=”--force-fsck

[$FSCKFIX”=”yes]&& fsck_fix=”--fsck-fix

...

exec mountall daemon $force_fsck $fsck_fix

end script

...

这是 mountall 的例子,该工作在系统启动时运行,负责挂载所有的文件系统。该工作需要执行复杂的脚本,由"script"关键字定义;在脚本中,使用了 exec 来执行 mountall 命令。

"start on" Stanza 和"stop on" Stanza

"start on"定义了触发工作的所有事件。"start on"的语法很简单,如下所示:

start on EVENT [[KEY=]VALUE]... [and|or...]

EVENT 表示事件的名字,可以在 start on 中指定多个事件,表示该工作的开始需要依赖多个事件发生。多个事件之间可以用 and 或者 or 组合,"表示全部都必须发生"或者"其中之一发生即可"等不同的依赖条件。除了事件发生之外,工作的启动还可以依赖特定的条件,因此在 start on 的 EVENT 之后,可以用 KEY=VALUE 来表示额外的条件,一般是某个环境变量(KEY)和特定值(VALUE)进行比较。如果只有一个变量,或者变量的顺序已知,则 KEY 可以省略。

"stop on"和"start on"非常类似,只不过是定义工作在什么情况下需要停止。

代码清单 3 是"start on"和"stop on"的一个例子。

清单 3. start on/ stop on 例子

#dbus.conf

description D-Bus system message bus

 

start on local-filesystems

stop on deconfiguring-networking

D-Bus 是一个系统消息服务,上面的配置文件表明当系统发出 local-filesystems 事件时启动 D-Bus;当系统发出 deconfiguring-networking 事件时,停止 D-Bus 服务。

Session Init

UpStart 还可以用于管理用户会话的初始化。在我写这篇文章的今天,多数 Linux 发行版还没有使用 UpStart 管理会话。只有在 Ubuntu Raring 版本中,使用 UpStart 管理用户会话的初始化过程。

首先让我们了解一下 Session 的概念。Session 就是一个用户会话,即用户从远程或者本地登入系统开始工作,直到用户退出。这整个过程就构成一个会话。

每个用户的使用习惯和使用方法都不相同,因此用户往往需要为自己的会话做一个定制,比如添加特定的命令别名,启动特殊的应用程序或者服务,等等。这些工作都属于对特定会话的初始化操作,因此可以被称为 Session Init。

用户使用 Linux 可以有两种模式:字符模式和图形界面。在字符模式下,会话初始化相对简单。用户登录后只能启动一个 Shell,通过 shell 命令使用系统。各种 shell 程序都支持一��自动运行的启动脚本,比如~/.bashrc。用户在这些脚本中加入需要运行的定制化命令。字符会话需求简单,因此这种现有的机制工作的很好。

在图形界面下,事情就变得复杂一些。用户登录后看到的并不是一个 shell 提示符,而是一个桌面。一个完整的桌面环境由很多组件组成。

一个桌面环境包括 window manager,panel 以及其它一些定义在/usr/share/gnome-session/sessions/下面的基本组件;此外还有一些辅助的应用程序,共同帮助构成一个完整的方便的桌面,比如 system monitors,panel applets,NetworkManager,Bluetooth,printers 等。当用户登录之后,这些组件都需要被初始化,这个过程比字符界面要复杂的多。目前启动各种图形组件和应用的工作由 gnome-session 完成。过程如下:

以 Ubuntu 为例,当用户登录 Ubuntu 图形界面后,显示管理器(Display Manager)lightDM 启动 Xsession。Xsession 接着启动 gnome-session,gnome-session 负责其它的初始化工作,然后就开始了一个 desktop session。

图 2.传统 desktop session 启动过程

init

|- lightdm

||-Xorg

||- lightdm ---session-child

||- gnome-session --session=ubuntu

||- compiz

||- gwibber

||- nautilus

||- nm-applet

|:

|:

|

|- dbus-daemon --session

|

:

:

这个过程有一些缺点(和 sysVInit 类似)。一些应用和组件其实并不需要在会话初始化过程中启动,更好的选择是在需要它们的时候才启动。比如 update-notifier 服务,该服务不停地监测几个文件系统路径,一旦这些路径上发现可以更新的软件包,就提醒用户。这些文件系统路径包括新插入的 DVD 盘等。Update-notifier 由 gnome-session 启动并一直运行着,在多数情况下,用户并不会插入新的 DVD,此时 update-notifier 服务一直在后台运行并消耗系统资源。更好的模式是当用户插入 DVD 的时候再运行 update-notifier。这样可以加快启动时间,减小系统运行过程中的内存等系统资源的开销。对于移动,嵌入式等设备等这还意味着省电。除了 Update-notifier 服务之外,还有其它一些类似的服务。比如 Network Manager,一天之内用户很少切换网络设备,所以大部分时间 Network Manager 服务仅仅是在浪费系统资源;再比如 backup manager 等其它常驻内存,后台不间断运行却很少真正被使用的服务。

用 UpStart 的基于事件的按需启动的模式就可以很好地解决这些问题,比如用户插入网线的时候才启动 Network Manager,因为用户插入网线表明需要使用网络,这可以被称为按需启动。

下图描述了采用 UpStart 之后的会话初始化过程。

图 3.采用 Upstart 的 Desktop session init 过程

init

|- lightdm

||-Xorg

||- lightdm ---session-child

||- session-init # <-- upstart running as normal user

||- dbus-daemon --session

||- gnome-session --session=ubuntu

||- compiz

||- gwibber

||- nautilus

||- nm-applet

|:

|:

:

:

##########NextPage[title=UpStart 使用]##########

linux

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/17123.html