1、本文所以内容来自 著名高校课件和学生笔记(校园里面经常见到有人高价买笔记)
2、任课教师不会提供参考文献,所以只能对作者表示感谢,如果引用了您的作品,可以用回复方式补充参考文献。
3、我不对文章无关问题进行解答,文章内容也比较难,我也很难解答您遇到的问题,如果发现BUG可以用回复方式帮我修正。
4、本课 计算机操作系统
,适用于计算机操作系统课、考研
本课其他部分的导航条见页面底部
§6.1 UNIX进程和存储管理简介
§6.2 UNIX进程结构
§6.3 进程控制
§6.4 UNIX进程调度与交换
§6.5 进程通信
§6.6 UNIX存储管理
本章小结
• 本章以UNIX System V
为主,介绍UNIX
的进程和
存储管理方法。
§6.1 UNIX
进程和存储管理简介
• UNIX
系统的核心部分从整体上说可以分为两大部
分,即“
静”
的文件系统和“
动”
的进程控制系统。文
件系统主要用来存放、管理那些暂时不被处理机执
行的程序和数据,它为程序和数据文件分配空间,
控制文件存取和为用户检索信息。而进程控制系统
则负责为将要执行的程序和数据文件分配内存空
间,并负责进程调度、控制并发进程的执行速度和
分配必要的资源,以及负责进程通信和内存管理等。
UNIX
的进程控制系统与文件系统之间通过系统调
用来互相作用。先介绍UNIX
的进程控制系统部分。
• UNIX
系统把一个程序看作是一个可执行文件,而
把一个进程看作是程序的执行或执行中的程序实例。
但是,从静态的观点看,CPU
把进程解释为由一组
机器指令、数据和堆栈结构组成的集合,及其上下
文。系统核心调度进程占据CPU
。由于调度并不一
定是在每个进程执行完毕时发生,因此,系统内同
时有多个进程在执行。而且,若干个进程可以同时
调用一个子程序。
• 和其他所有操作系统一样,UNIX
操作系统只有在
其内核装入内存后才能开始运行。
• 为了使操作系统内核能在每次开机时顺利地装入内
存,用户必须事先把UNIX
操作系统的执行代码以
文件方式存储在计算机硬盘设备中,并对计算机系
统中的相应资源,例如高速缓存、交换区等进行初
始化。这一过程被称为操作系统的安装过程。一个
商用的操作系统都有自己的自动安装程序。用户在
购买了操作系统之后,只要按照操作系统程序的提
示和说明,一般都能进行系统安装。因此,本章的
进程运行和存储管理都是假定在一个已完全安装完
毕的操作系统基础上进行的。
• 在一个已安装好UNIX
系统的操作系统中,启动电
源意味着系统引导程序开始系统自举,引导在外存
硬盘中的操作系统进入内存。这一过程是一个启动
UNIX
系统、设置和初始化各种数据结构与表格、
建立控制UNIX
系统内核运行的控制进程(在UNIX
系统中,把核心进程称为0
#
进程),和建立控制终
端进程与Shell
lShe
进程(用户交互进程)运行的1
#
进程。
最后,系统在建立了0
#
进程和1
#
进程等之后,将出
现相应的提示符,以等待用户输入命令来执行和处
理用户应用程序。
• UNIX
系统在初始过程中的运行如图6.1
所示。图
中,当系统创建了1
#
进程之后,1
#
进程将会调用相
应的终端管理进程,为UNIX
系统的不同终端创建
相应的终端管理进程和Shell
lShe
进程,从而使每个终端
上的用户都可以在Shell
lShe
的管理下交互使用UNIX
系
统。
图6.1 UNIX
中各进程的关系
• Shell
lShe
程序将为用户提供解释执行用户命令的交互工
具。随着用户命令,例如“
cp
”
等的输入,系统将为
该命令建立一个执行该命令的用户进程。如果这个
用户进程抢不到处理器,则Shell
lShe
进程会自动退出处
理器,进入等待队列,以便用户进程执行。在用户
进程执行结束后,Shell
lShe
进程又恢复执行,并显示提
示符和等待用户的下一条命令输入。UNIX
系统的
所有进程都是在上述执行过程中产生和消亡。
• 由图6.1
可以看到,在UNIX
系统中还未创建出其他
新用户进程之前,只有0
#
进程、1
#
进程以及终端管
理进程与Shell
lShe
进程存在。其中,终端管理进程与
Shell
lShe
进程是1
#
进程的子进程,这是因为在UNIX
系
统中,除了0
#
进程和1
#
进程之外,其他进程都是由
父进程创建的。人们也称1
#
进程是所有用户进程的
祖先。
• UNIX
操作系统的0
#
进程在核心态下运行,而1
#
进程
以及由1
#
进程衍生的其他进程都可在用户态和核心
态两种执行模式下执行。
• 在不同的执行模式下执行时,同一进程使用不同的
堆栈和不同的管理数据结构。在两种不同模式下执
行的程序不能互相访问各自的堆栈,它们之间的参
数传递往往需要借助通用寄存器等硬件。两态之间
的主要区别是,用户态下的进程能存取它们自己的
指令与数据,但不能存取核心指令和数据。然而,
核心态下的进程能存取核心和用户地址。另外,某
些机器的指令是特权指令,在用户态下执行会引起
错误,只能在核心态下执行。另外,在后面的章节
中将会看到,核心态模式享有比用户态模式高的优
先级。因此,尽管是同一进程,有时仍把它分开称
为用户进程和系统进程(核心进程)。
• 进程与1
#
进程是UNIX
系统中最重要的两个进程。
其中,0
#
进程是UNIX
系统中唯一只在核心态下执
行的进程。它有三种功能,除了在初始化时创建1
#
进程之外,还负责调度分配处理器以及负责进程交
换。有关UNIX
进程调度和交换功能将在本章后续
部分介绍。
• UNIX
进程的核心态和用户态之间的转换靠中断以
及硬件设置等方法完成,当用户进程由用户态转向
核心态执行时,需要依靠中断或后述的陷阱来实现。
在核心态执行的进程只有通过设置程序状态寄存器
PSW
才能回到用户态。它们之间的关系如图6.2
所
示。
图6.2 UNIX
进程的核心态与用户态之间的转换
• 系统在逻辑上由四个模块组成。即与文件系统的接
口部分,进程本身的控制部分,包括进程的创建、
进程调度和进程的撤消等,第三部分是进程间控制
部分,包括进程间的互斥、同步和通信等,第四部
分是存储管理部分。进程控制系统模块结构如图
6.3
所示。
图6.3
进程控制系统
• 进程控制系统与文件系统的接口有两个,一个是在
系统内部与文件系统直接发生联系的有关表格和数
据结构。另一个则是通过系统调用界面,也就是中
断和陷阱(Interrupt
&Trap
)总控部分与文件系
统发生联系。以便把待执行的文件读入内存,或把
已经执行完毕的程序和结果写入文件系统长期保存。
• 调度模块的作用是分配CPU
。显然,在进行资源分
配、特别是CPU
分配时要按照一种既公平合理又
有很高效率的分配原则。在UNIX
系统中,这个调
度原则就是按照进程的优先级,每次调度具有最高
优先级的进程去占有处理机。每一个进程,从它被
创建的那一时刻起,就具有了一个随时间动态变化
的优先级。在UNIX System
Ⅴ
中,系统有两个时
机计算各进程的优先级。这两个时机是:
• (1)
每秒钟一次的时间片结束发生时钟中断时,对
那些优先级大于某个常数的进程进行重新计算。
• (2)
当前执行进程请求系统调用后,从中断和陷阱
总控程序返回当前执行的用户态时,重新计算当前
执行进程的优先级。
• 这里要指出的一点是,系统计算各进程优先级的时
间并不总是发生进程调度的时间。
• UNIX System
Ⅴ
中引起进程调度的情况有五种:
• (1)
当前执行进程申请内存等系统资源未得到满
足,从而自己调用sleep
过程,
放弃处理机进入睡眠
状态。
• (2)
为了与其他并发进程保持同步,调用了wait
tawi
或
stop
过程等,从而主动放弃了处理机而进入睡眠状
态。
• (3)
当系统发现系统中某进程的优先级已高于当前
执行进程的优先级时,系统设置一个名叫runrun
的
调度标志。但是,系统并不在runrun
标志刚被设置
时就开始调度。它要等待到系统在核心态下的程序
执行完毕,由核心态转入用户态时,也就是在中断
陷入总控处理程序结束之前的瞬间,检查runrun
标
志并进行调度。
• (4)
时间片用完,且当前进程的优先级低于其他就
绪进程。
• (5)
当前进程调用exit
texi
,自我终止时。
• 进程通信是UNIX System
Ⅴ
的一个重要组成部分。
进程通信既包括用来控制各并发进程执行速度和资
源共享与竞争的低级通信,也包括进程之间大量传
递信息的高级通信。
• UNIX
系统在核心态下执行时,系统进程只能借助
sleep
原语和wakeup
(或set-run
)原语实现同步。
sleep
原语使当前执行进程以指定原因和优先数睡
眠,而wakeup
则唤醒在指定原因上睡眠的所有进
程。用户进程不能使用sleep
原语和wake-up
原语。
用户进程之间要实现同步通信的话,一种办法是利
用系统核心提供的软中断信号进行通信。UNIX
System
Ⅴ
为用户使用软中断通信提供了相应的系
统调用。另一种办法是调用系统调用wait
tawi
或sleep
使
得当前执行进程进入等待状态,直到所等待事件发
生时由核心唤醒或睡眠到一定时间后自动唤醒。用
户进程之间实现同步的高级办法是使用System
Ⅴ
提供的信号量方法。System
Ⅴ中的IPC
模块为进程
间的大量信息传送提供了众多的系统调用。
• 除了上述通信手段之外,UNIX
还提供了一种称之
为管道(pipe
)的信息传送手段。它以临时文件的
方式,实现同一主机内的进程之间批量数据的单向、
先进先出方式的无格式字符流传送。
• 存储管理模块控制存储分配。任何一个待执行进
程,如果它不能在内存中占据必需的容量,它是不
能执行的。换句话说,CPU
绝对不会执行一个全
部内容都在外存的进程。然而,内存是一种有限而
又昂贵的资源,它不可能容纳系统中全部活动进程。
存储管理系统必须决定把哪一个进程的哪一部分留
在内存中,而把哪一部分放在外存。也就是说,存
储管理部分管理进程在内存和外存之间的信息转
移,以便所有进程都得到公平执行的机会。
• 下面先介绍UNIX
系统的进程结构。
§6.2 UNIX
进程结构
• 本节将进一步介绍UNIX System
Ⅴ
进程的静态构
成,定义进程上下文及其状态转换等。
6.2.1
进程的概念
• 在UNIX
系统中,进程被赋予了下述特定的含义和
特性:
• (1)
一个进程是对一个程序的执行。
• (2)
一个进程的存在意味着在所谓的“
proc
”
数组
(PCB
的常驻内存部分)中有一个非零的结构存
在,它包含着相应的进程控制信息。
• (3)
对于每一个进程有一个被称为U
区或user
erus
结构的
数据结构。这个数据结构放置该进程的私用控制信
息,且在进程被创建时才会由系统分配相应的域。
• (4)
一个进程可以生成或消灭其子进程。
• (5)
一个进程是获得和释放各种系统资源的基本单
位。
• 上述第(1)
点是反映进程动态特性的,而第(2)
点与
第(3)
点又反映了进程的静态特性。第(4)
点与第(5)
点反映了UNIX
系统的进程之间的关系以及UNIX
没
有作业概念的特性。事实上,由第3
章可知,一个
进程的静态描述是由三部分组成的,即进程状态控
制块PCB
(栈段),进程的程序文本(正文)段以
及进程的数据段。在第3
章中,把这三部分统称为
进程上下文,而进程的动态特性则定义为在进程上
下文中的执行。
• 首先介绍UNIX System
Ⅴ
进程的虚拟地址结构。
• 由于UNIX System
Ⅴ进程的虚拟地址结构是依赖于
硬件,因此,如果不作特别说明,本文默认那些与
硬件有关的部分都是依赖于VAX11
的。
6.2.2
进程的虚拟地址结构
• 如上所述,UNIX System
Ⅴ
的进程由三个逻辑段
组成:即存放状态控制块的栈段、存放CPU
执行
指令集合的正文段以及被执行指令所访问的数据段。
UNIX System
tIeNUXmSys
Ⅴ
中,一个进程的虚拟地址空间被分
成若干个逻辑区(logical region
)来存放上述三个
逻辑段。区是进程虚拟地址空间上的一段连续区
域,它是被共享、保护以及进行内存分配和地址变
换的独立实体。正文、数据和栈分别存放于各自的
区中。
• 这里,要强调的一点是进程的虚拟地址在各区之内
是连续的。
• 为了管理每个进程中的区,系统设有一个称为区表
的数据结构,每个在系统中存在的区都在该表中占
有一个表项。区表包括下列内容:
• (1)
区的类型,指明该区存放正文段、数据段或私
有数据及栈段。
• (2)
区的长度。
• (3)
区所对应页表的内存始址。
• (4)
区的状态,包括是否已被调入内存,是否正在
调入内存过程中,是否被锁住,以及是否正在被请
求调入内存等。
• (5)
共享位,给出共享该区的进程数。
• (6)
文件系统指针,指向外存中与该区对应的数据
文件。
• 区表如图6.4
所示。
图6.4
系统区表
• 在系统创建新进程时,核心将从区表中分配相应的
表项给所创建的进程。
• 为了把区表和进程联系起来,当进程中的某个逻辑
段在区表中分得表项并填写了相关栏目之后,将把
该表项的内存地址返回到进程的proc
结构中。proc
结构中与区表项有关的还有该段在虚存空间的起始
地址,内存中的页表地址及页表长度等。关于proc
结构,将在后面讲述。
• 把区表和进程proc
结构分开的原因之一是便于共
享,因为每个逻辑区(段)在不同的进程中对应的
虚拟地址是不同的,但它们却可以通过区表而对应
变换到同一物理内存空间。区表和进程proc
结构的
关系如图6.5
所示。
图6.5
区表与进程proc
结构
• 在系统创建一个进程或让一个进程共享其他进程的
某个段时,在分配区表项后或在改变有关区表项共
享计数位后,把这些区表项与有关进程连接起来。
对新进程的连接是在创建proc
结构时填写区表项地
址,该区表项对应逻辑段的虚拟地址、所需页表的
内存始址、逻辑段长度等。对共享段的连接只要填
写区表项地址、页表内存始址和长度即可。但是,
共享段的虚拟地址在不同的进程中是不一样的。
• 在区表的讨论中,大家也可能注意到一点,即
UNIX System
Ⅴ
中的区和段页式管理中的段非常
相像。所不同的是,段页式管理中的虚拟地址空间
是二维的,而UNIX System
Ⅴ的各个进程的分区虚
拟地址仍是一维的。另外,UNIX System
Ⅴ
的分
区并不是由用户按照段的逻辑功能独立定义,而是
由系统设计人员预先设置好的。
6.2.3
进程上下文
• UNIX System
Ⅴ
的进程上下文是由正文段,也就
是CPU
执行指令的集合、核心数据结构、和有关
寄存器的内容与数据段组成。
• 1.
进程上下文的基本结构
• 进程上下文的各个部分按照一定的规则分布在进程
虚拟空间的不同位置上。对于不同的机器和硬件结
构,进程上下文的分布规则不同。例如,在VAXVAX-
11
型机上,其虚拟地址空间划分为进程空间和系统
空间两大部分。其寻址范围为
2
32
个单元,即
4096M
位。其中,虚拟空间的低位地址的半部分
(0 ~ 2
31
-1
)是进程虚拟空间,其余为所有进程共
享的系统空间,操作系统核心程序占据这个区。
• 进程虚拟空间又分为程序区P
0
和控制区P
1
,其中P0
区用来放用户程序,也就是进程上下文中的正文段
代码。这个段的起始虚址为0
,且可以动态地向高
地址方向增长。P
1
区容纳各种方式的栈以及存放受
保护的进程专用代码和数据,P
1
区从2
31
-1
单元开始
向低地址方向增长。进程空间基本结构如图6.6
。
• 在图6.6
中,核心态栈(kernal
stack
taksc
)是该进程执
行核心程序时,保留的核心栈副本。该栈中装有进
程调用核心函数时用到的有关参数等,另外,还包
括系统调用的调用序列。设置核心栈的目的是使进
程在执行了不同调用顺序的核心函数之后,仍能返
回到原来的用户态下执行。核心栈具有多个层次,
其中每层可保留一次调用或中断处理后,返回被中
断程序处继续执行所必需的有关寄存器的值。
图6.6
进程空间结构
• 用户栈含有在用户态下执行时函数调用的参数、局
部变量及其他数据。图6.7
给出了执行copy
程序时
用户栈和核心栈的变化例。图6.7
的左侧描述了当
由
main (
argc,argv
)
过程调用
copy (old,new),
,)过程
copy (old,new)
更进一步调用库函数
write ()
来调用
write
的内部结构。系统调用使用专门的陷阱指令
trap
,执行trap
指令将产生一个中断,使得进程的
执行模式由用户态转换为核心态。
• 然后,用户态执行转变为核心程序执行,
并使用核
心栈。
• 由于内核保护的原因,用户栈和核心栈之间不能互
相传递参数。因此,如果要把用户程序中的参数传
递给核心函数,必须通过通用寄存器和进程的PCB
结构。
图6.7
执行copy
程序时用户栈和核心栈的变化
• 进程空间的用户进程正文段、数据段、用户栈、核
心栈以及有关的专用代码和数据是以进程为单位独
立的。它们根据需要换进换出内存。
• 在系统虚拟空间部分存放的进程上下文部分是:系
统程序用页表、进程页表、proc
结构、核心正文段
和数据段等。系统虚拟空间的内容常驻内存,不因
内存的大小或执行情况而换进换出。另外,由于核
心正文段和与它们有关的数据结构、系统页表是被
所有进程共享的,在UNIX
系统中,不把它们看作
进程上下文的一部分。
• 2.
进程上下文的组成部分
• 进程上下文由proc
结构、user
erus
结构、用户栈和核心
栈的内容、用户地址空间的正文段、数据段、硬件
寄存器的内容以及区表和页表等组成。
• proc
结构
• UNIX
的proc
结构和user
erus
结构相当于在第3
章中介绍
的进程控制块PCB
。之所以把进程控制块分成两
部分的原因是user
erus
结构中主要包含那些只有进程执
行时才被使用的控制信息,从而,这些信息可以不
必常驻内存而节省内存空间。
• UNIX System
Ⅴ
的proc
结构主要包括以下各项:
• (1)
标识进程的状态用的状态位。UNIX System
Ⅴ
共有9
个状态编码。
• (2)
若干用户标识号,简称UID
或用户ID
。这些用
户标识号指出该进程属于哪一组用户,具有何种特
权,例如是否可以互相发送软中断等等。
• (3)
若干进程标识号,简称PID
或进程ID
,说明进
程相互间的关系。
• (4)
存储区位置和长度,指明进程在内存或在外存
中的位置及大小。这些信息在进程换入换出,以及
状态转换等时用到。
• (5)
调度参数,包括优先数等。核心用它们决定进
程转换到核心态和用户态的次序以及占有处理机的
次序。
• (6)
软中断信号项,记录发向一个进程的所有未处
理的软中断信号。
• (7)
各种计时项,给出进程执行时间和系统资源的
利用情况。这些信息用来为进程计账、计算调度优
先权,以及发送计时信号等。
• (8) user
er8u)结构的起始地址项。
• (9)
进程页表指针,用于CPU
访问内存时的地址变
换。
• user
结构
• user
erus
结构则主要包括以下各项
• (1)
指向proc
结构的指针,标识出对应于该user
erus
结构
的proc
结构。
• (2)
一个含有系统调用结果的返回值项,当系统调用
执行结束之后,所得结果存放该项中以便用户程序
可以使用。
• (3)
与用户标识有关的若干项,它们决定进程的各种
权限,如存取权限等。
• (4)
与文件结构有关的若干项,它们描述文件的当前
目录和当前根,以及进程的文件系统环境。
• (5)
与文件读写有关的若干项,描述所要传送的数据
量,在用户空间的源(
或目的)数据的数组地址、读
写的文件字节数、读写方式、缓冲区长度与地址等。
• (6)
用户文件描述符表,记录该进程已打开的文件。
• (7)
中断及软中断处理的有关参数,依靠这些参
数,进程对所收到的软中断信号作出不同的反应。
• (8)
出错管理项,记录系统调用过程中遇到的错
误,以便系统或进程做相应的处理。
• (9)
对该进程创建的所有文件设置许可权方式字段
的屏蔽模式项。
• (10)
与上下文切换、现场保护有关的各项,它们保
存通用寄存器的用户区地址,保存各种寄存器的当
前值,进程的核心栈和用户栈指针,程序计数器和
处理机状态字等当前值。
• (11)
各种计时项,记录进程及其后代在用户态和核
心态下执行时各自所用的时间。
• (12)
进程数据段、正文段、栈段长度。
• 由以上proc
结构与user
erus
结构的组成可知,proc
结构
中存放的是系统感知进程存在所必需的数据和信
息,而user
erus
结构中存放的是进程执行时所必需的各
种控制数据和信息。因此,系统在内存中开辟有专
用的proc
结构区域,使proc
结构常驻内存且系统可
存取访问任一proc
结构。而user
erus
结构则不常驻内
存,且只有当一个进程被创建成功时,系统才为其
分配user
erus
结构空间。user
erus
结构的各项只能由其执行
中的进程自己访问存取。关于用户栈和核心栈已在
上一小节中作了说明,这里不再重复。
• 寄存器内容
• 进程上下文所包含的寄存器内容有:
• (1)
程序计数器PC
的内容,指出CPU
将要执行的下
条指令的虚拟地址。
• (2)
处理机状态寄存器的内容,称为处理机状态字
PSW
,PSW
给出机器与该进程相关联的硬件状态。
• PSW
包含当前执行进程的访问方式,即是在核心
态下还是在用户态下执行。另外,还包含中断优先
级,以及中断或陷入之前的访问方式等。
• (3)
栈指针,指向栈中下一项的当前地址。至于指
针是指向核心栈还是用户栈,则由CPU
执行方式
确定。
• (4)
通用寄存器,用来存放进程在执行期间所产生
的中间结果或参数。例如,通用寄存器R0
和R1
就
是在用户进程与系统进程之间传递参数和返回值时
用的。
• 区表和页表
• 区表和页表也是进程上下文的内容之一。它们定义
了进程各部分从虚拟地址到物理地址的映射。如果
存在多个进程共享某个公用区(正文区或数据
区),那么这个公用区将是每个进程上下文的一部
分(注意,这对系统程序是不成立的)。
• 进程正文段、数据段
• 进程正文段、数据段和用户栈等一起占据进程的虚
拟地址空间(0~ 2
02~
31
-1
)部分,由区表和页表等组
成的地址变换机构将其虚拟地址变换为内存物理地
址。由于 UNIX System
Ⅴ
采用交换操作和请求
页式虚存,因此,进程虚拟地址空间的许多部分不
是总驻留在内存中,但它们仍是进程上下文的一部
分。这一点与UNIX
的早期版本有区别。
6.2.4
进程的状态和状态转换
• 一个进程的生命期是由一组状态来刻画的。这些状
态是进程proc
结构的一部分。
• UNIX System
Ⅴ
中进程共有9
个状态,它们是:
• (1)
进程在用户态下的执行态SRUN
SNUR
。
• (2)
进程在核心态下的执行态SRUN
SNUR
。
• 进程是在用户态下还是在核心态下执行主要由处理
机状态字PSW
来区别。
• (3)
进程处于就绪态SRUN
SNUR
,只要核心程序调度到
它,就可投入执行。
• (4)
进程处于就绪态SRUN
SNUR
,但交换程序已将其换出
内存。只有等待交换程序把它换入内存之后,核心
才能调度它去执行。
• (5)
进程正在睡眠,且驻留在内存中的状态SSLEEP
SPESL
。
• (6)
进程正在睡眠,但交换程序已将其换出内存的
状态SSLEEP
SPESL
。
• (7)
进程正从核心态返回用户态。但核心抢先于它
作了进程上下文切换,以调度别的进程执行。最
后,当该进程再次被调度到时返回用户态。
• (8)
进程刚被创建时,由于正在进行资源分配,因
此,既不是就绪态,也不是睡眠态。这个状态可被
认为是进程的初始状态。
• (9)
进程执行了系统调用exit
texi
后,进入僵死状态。
• 图6.8
给出了UNIX System
Ⅴ
的进程状态转换图。
图6.8
进程状态转换图
• 图6.8
反映了一个进程从被创建到被释放的整个生
命周期内的变化过程。状态之间的转换有些是通过
系统原语或核心函数完成(例如唤醒或调度等)。
有些则由外部事件的发生而导致状态转换(例如陷
阱或中断)。
• 首先,当父进程执行系统调用fork
时,被创建进程
进入图中状态8
,即创建状态。在该状态时,核心
为该进程分配user
erus
结构区以及必要的内存工作集。
内存管理分配程序如果能为该进程分配足够的内
存,则进程状态发生变化,由状态8
进入内存就绪
状态3
。此时,由于该进程已分得存放user
erus
结构,
各种页表、堆栈、部分正文段和数据段所用的内存
空间,因此,该进程可以经调度选中后占有CPU
。
• 如果内存分配程序不能为该进程分配足够的内存,
则该进程的进程上下文被放入外存交换系统中,进
程由状态8
进入外存就绪状态5
。如果进程处于状
态5
,则只有在交换程序将进程上下文换入内存成
为状态3
之后,才有可能被调度执行。
• 当进程进入状态3
后,进程调度程序将会在适当时
机选择该进程去执行。这时,该进程在核心态下执
行,以装配该进程的进程上下文。在这个状态下,
该进程完成有关fork
部分的工作。
• 当该进程完成fork
系统调用后,它可能返回用户态
下执行用户程序,这时进入状态1
。
• 另外,在进程完成系统调用后返回用户态之前,根
据UNIX System
Ⅴ
的调度时机规定,此时若有优
先级高于当前进程的进程存在,则系统将调度优先
级高的进程去占据处理机,从而进入状态7
。
• 进程进入状态7
之后,所处的地位与状态3
相同,
即要等到再一次进程调度时,才能返回用户态。
• 当 进程处于状态1
时,用户程序中由于使用系统调
用或由于输入输出数据等而发生陷阱与中断。这
样,进程又进入状态2
而变为在核心态执行。
• 进程在核心态执行时,因为等待某事件发生,例如
等待输入输出完成时,调用sleep
原语进入睡眠状
态。处于睡眠状态的进程因为内存的限制,将在睡
眠一段时间后被交换程序换出内存而进入外存睡眠
状态6
,直到事件发生后被唤醒原语唤醒而进入状
态5
。
• 在进程完成它所要求任务之后,将使用系统调用
exit
texi
,从而使得进程进入僵死状态9
而释放资源。
6.2.5
小结
• 在本节中,讨论了UNIX System
Ⅴ
中进程的虚拟
地址空间,并介绍了进程的上下文和进程的状态及
转换。进程的虚拟地址空间是进程管理和内存管理
的基础,UNIX System
Ⅴ采用了分区连续虚拟地址
空间的方法。这使得进程之间程序或数据段的共享
更加容易。
• 进程上下文是进程的静态描述。proc
是系统感知进
程存在的唯一实体。proc
结构中的各项是系统调度、
控制进程必需的,因此,必须常驻内存。反过来,
user
erus
结构是进程执行时才要用到的控制信息,因
此,如果一个进程不在执行过程中,其user
erus
结构是
不必调入内存且不能被系统或其他进程所访问的。
进程上下文中的正文段和数据段是进程完成所要求
任务的关键部分,通用寄存器、程序计数器以及处
理机状态寄存器和页表、区表等都是为了正文段的
顺利执行而用来存放中间结果、传递参数,或存放
下条指令的虚拟地址,或区别控制CPU
的访问模
式和完成地址变换等功能的。进程上下文各部分构
成十分巧妙,缺一不可。
• 另外,进程可以在用户级对某些状态的转换加以控
制。例如,用户可以创建进程,可以利用系统调用
从用户态进入系统态。但是,有些状态转换是由系
统控制的。例如,被创建进程是转换到内存就绪态
还是外存就绪态取决于内存管理程序。有些状态转
换则要依靠外部事件和系统的共同控制。例如,一
个处于睡眠态的进程何时能转换成就绪态则依赖于
事件的发生和唤醒原语。
• 总之,进程的上下文和状态转换刻画了UNIX
进程
的静、动两种特性,它们是进程的完整反映。
§6.3
进
程
控
制
6.3.1 UNIX
启动及进程树的形成
• 系统管理员首先通过自举把操作系统装入内存,并
开始执行它。自举过程是由系统管理员按动某个特
殊的按钮来指示机器从它的微代码装入启动程序的。
UNIX
系统的自举过程是读一个磁盘的引导块(文
件系统的第0
块),并将其装入内存,在核心装入
内存后,系统开始执行启动过程start
。启动过程
start
首先初始化系统内部数据结构。例如,构造
空闲缓冲区、初始化区结构、页表项等。然后,系
统将根文件系统安装到根“
/”
下,并建立系统调度
进程的proc
结构proc
[0
]
,并使根“
/”
成为进程0
的当前目录。
• 在创建和设置好进程0
的环境之后,系统就作为进
程0
执行并调用fork
过程创建新进程1
(这里的fork
不是系统调用),也就是设置proc
[1
]
的有关表
项。进程1
在系统中被称为init
itni
进程。它是一个既可
在核心态,又可在用户态运行的进程,它的正文代
码由调用系统调用exec
cexe
执行程序“
/etc
/init
”
的代
码组成,进程1
负责初始化所有新的用户进程。
• 进程1
调用exec
cexe
执行“
/etc
/init
itni
”
程序后,为每个终
端生成一个子进程,然后等待用户在终端上注册。
• 用户在终端上输入命令,每个命令都对应于一个可
执行文件。shell
命令解释程序解释此命令,找到相
应的可执行命令文件,用系统调用fork()
创建子进
程,并由此子进程调用系统调用exec()
执行此命令
文件;父进程也就是终端进程则处于等待状态,子
进程执行文件结束后调用系统调用exit()
自我终止。
唤醒父进程做善后处理并转而显示提示符,准备接
受下一条命令执行。
• 进程启动及进程树的形成过程如图6.9
所示。
图6.9
进程树的形成
6.3.2
进程控制
• 1.
进程的创建
• 该节主要讨论用户进程的创建、执行和自我终止问
题,与此相对应,UNIX
系统提供有相应的系统调
用fork( )
,exec( )
和exit( ),
,(以便在用户级上实现上述
功能。
• fork
的功能是创建一个子进程。调用fork
的进程称
为父进程。
• 系统调用fork
的语法格式是:
pid
dpi
=
fork ( ) ;
• 从系统调用fork
返回时,父进程和子进程除了返回
值pid
dpi
与proc
结构中某些特性参数不同之外,其他
完全相同。CPU
在父进程中时,pid
dpi
值为所创建子
进程的进程号,若在子进程中时,pid
dpi
的值为零。
• 为了便于理解UNIX
系统进程的并发性,下面介绍
一下fork
的功能与实现过程。
• 系统调用fork
通过执行核心程序fork
过程完成的功
能是:
• (1)
为子进程在proc
结构表中分配一个空项。
• (2)
为子进程赋一个唯一的进程标识号pid
dpi
。
• (3)
复制一个父进程上下文的逻辑副本。这里的逻
辑副本是指不把父进程中那些可被共享的部分复制
到新的内存区中,而只改变共享区的引用数。但
是,对于父进程的非共享区部分则复制到新的内存
区中。
• (4)
增加与父进程相关联的有关文件系统的进程引
用计数。
• (5)
对父进程返回子进程的进程标识号,对子进程
返回零。
• 下面介绍fork
算法。其算法流程图如图6.10
所示。
• 在图6.10
中,系统首先检查有无足够的内存或外存
交换空间存放子进程的上下文。在资源满足的条件
下,系统在proc
结构中为子进程分配一空表项,并
开始构造子进程的上 下文。
• 系统在分配给用户proc
结构表时,对用户同时拥有
的进程个数有一定的限制,以免妨碍其他用户创建
进程。另外,普通用户不能占用proc
结构表中的最
后一个表项,以防系统发生死锁而无法正常退出。
再者,系统为新创建进程所分配的标识号按比最近
一次分配的进程标识号大1
的顺序递增。当标识号
达到所规定的最大值之后,则从0
开始重新循环。
图6.10 fork
流程图
• 紧接着,系统从父进程proc
结构中,把除了pid
dpi
等
之外的大部分项复制到子进程proc
结构中。然后,
系统设置子进程的各种调度参数,并把子进程状态
置为SIDI
ISDI
(创建态)。
• 然后,系统调整进程与文件的接口,使得子进程自
动共享父进程所打开的文件,以及确定子进程在文
件系统中所处的目录位置(有关文件系统,将在后
面的章节中讲述)。
• 下一步,系统将把进程的上下文中的寄存器内容保
存在父进程的fork
专用保存区(fork
的核心栈)中。
系统在保存的寄存器内容中,包括程序计数器和处
理机状态字等内容。这些内容将在后述各步中复制
给子进程,以便子进程执行时能识别出自己是子进
程,并从这里开始执行。
• 接着,系统开始把父进程的上下文复制到子进程中
去。这包括为子进程的user
erus
结构区及页表等分配内
存和进行复制。另外,如果父进程的正文段和数据
段不允许共享的话,则也要将这些非共享部分复制
到子进程的内存区或外存区中。对于那些允许共享
的部分,则只要增加相应的共享计数值就行。子进
程的user
erus
结构除了指向proc
结构表项的指针与父进
程的不同之外,其他部分与父进程的user
erus
结构完全
相同。
• 以上复制的上下文部分是进程的静态部分,除了复
制父进程的静态上下文之外,系统也将保存有寄存
器内容的核心栈内容复制到子进程的核心栈上去。
以利于进程能从系处开始执行。注意在有的计算机
中,核心栈是作为user
erus
结构的一部分实现的,因此
不必再另外需要内存和进行专门的复制。但有些计
算机中,核心栈不是user
erus
结构的一部分,此时,则
需把核心栈复制到子进程的一个私有存储区上。
• 由于复制子进程的上下文需要足够大的内存,有
时,内存空闲区是不能满足这个要求的。这时,上
述复制只好在虚空间完成,也就是说,所创建的子
进程上下文将被换出内存空间。否则,父进程将子
进程的状态改为“
内存就绪”
之后,从核心态准备返
回到用户态。如果此时不发生进程调度和不调度到
子进程执行,则父进程将子进程的pid
dpi
返回给用户
后回到用户态执行。否则,调度算法调度到子进程
执行,子进程返回零值给用户后,完成fork
调用返
回用户态执行。
• 2.
执行一个文件的调用
• 当父进程使用fork
创建了子进程之后,子进程继承
了父进程的正文段和数据段,从而限制了子进程可
以执行的程序规模。那么,子进程用什么办法来执
行那些不属于父进程正文段和数据段的呢?这就是
利用系统调用exec( )
或exece
cexe
( )
。系统调用exec
cexe
引出
另一个程序,它用一个可执行文件的副本覆盖调用
进程的正文段和数据段,并以调用进程提供的参数
转去执行这个新的正文段程序。
• 系统调用exec( )
包含六种不同的调用格式,但它们
都完成同一工作,即把文件系统中的可执行文件调
入并覆盖调用进程的正文段和数据段之后执行。有
关exec
cexe
的各种系统调用的区别主要在参数处理方法
上。这些系统调用使用不同的输入参数、环境变量
和路径变量。
• 这里,系统调用execvp
()
和execlp
()
在程序中经常用
到,其调用格式是:
execvp
(filename
,argp
)
,
或
execlp
(filename
,arg0
,arg1
,...
,(char
*
)0);
• 其中,filename
ilfenam
是要执行的文件名指针,argp
是输
入参数序列的指针,而0
则是参数序列的结束标志。
• 例:用execlp
调用实现一个shell
的基本处理过程。
• 利用fork-exec
可实现一个shell
的基本功能。用户
输入命令后,按以下步骤执行用户命令(图6.11
)。
• (1)
利用fork
,创建子进程。
• (2)
利用exec
cexe
,启动命令程序。
• (3)
利用wait
tawi
,父进程和子进程同步。
图6.11 shell
l6h.执行过程
• 用C
语言实现的程序例如下。
#include
〈stdio.h
〉
main ( )
{
char command
[32
]
;
char
*
prompt =
“
$
”
;
while (
printf
(
“
%s
”
,prompt) ,gets (command) != NULL)
{
if (fork () == 0)
execlp
(command
,command
,(char
*
)0) ;
else
wait (0) ;
}
}
• 上面实现的shell
中,不包含路径检索功能(即执行
有关命令时,必须把从根开始至命令名为止的路径
名全部输入),也没有包括参数处理功能。此例只
是为了说明exec
cexe
调用的应用以及fork
与exec
cexe
的关系。
• 3.
进程的终止
• 系统调用exit(rv
tervxi
)
自我终止当前进程,使其进入
SZOMB
僵死状态,等待父进程进行善后处理。
• exit
texi
调用将导致释放除proc
结构之外的所有资源,
并清除进程上下文。父进程在收到子进程的信息rv
和有关子进程的时间信息之后,将释放子进程的
proc
结构和将有关时间信息加到自己的proc
结构的
有关项中去。
§6.4 UNIX
进程调度与交换
• UNIX
系统的调度与交换都是进程0
的两个部分。
它们分别由
swtch
()
过程和sched
scdhe
()
)(
过程实现。事实
上,用于交换的sched
scdhe
过程是把处于外存就绪态的
进程换入内存,相当于三级调度中的中级调度
(UNIX
系统中没有高级调度)。因此,有时也把
进程0
称为调度进程。下面分别介绍进程的调度与
交换。
6.4.1
进程调度
• 1.
调度原理
• UNIX
系统的进程调度采用多级反馈轮转调度法
(Round
Robin
onRbi
with
Multiple Feedback
itedkpuM )。
即系统给进程分一个时间片,当时间片结束时,动
态计算该进程的优先级,若有优先级高于当前进程
的内存就绪态进程时,系统设置调度标识,在由核
心态转换到用户态前由swtch
过程调度优先级高的
进程执行,并把被抢先的进程反馈到相应的优先级
队列中。一个进程在它结束之前,可能要经过多次
反馈循环。
• UNIX
的进程调度按时间片计算优先级,
并按优先级
的高低来调度进程,
抢占处理机。因此,UNIX
系统
的进程调度是基于时间片加优先级的。
• UNIX
的进程调度涉及的主要问题是:
• (1)
调度的时机。
• (2)
调度标志设置。
• (3)
调度策略与优先数的计算。
• (4)
调度的实现。
• 下面,分别说明这几个问题。
• 2.
调度的时机
• 在UNIX
系统中,为了减少操作系统设计的复杂性
和提高系统执行效率,对操作系统程序采用了伪异
步执行方式。也就是说,设计人员认为在系统程序
执行期间不会发生调度或发生调度的时间是可预知
的。然而,由于调度程序swtch
又是进程0
的一部
分,也就是说是系统程序,这又要求调度必须在核
心态下完成。怎样把这二者统一起来呢?显然,采
用系统调用的方式向用户开放进程调度是不可取
的,这一是导致系统无法控制,二是可能造成系统
瘫痪和很多意想不到的问题出现。UNIX
的设计者
们采用了当处理机在执行完核心程序之后向用户态
转换之前的瞬间,
检查各就绪进程的优先级进行调
度的方法。由用户态转而执行核心程序的可能性很
多。例如中断处理和陷阱处理,系统调用等。
• 另一种可以切换处理机的时机是:当进程因申请系
统资源而未得到满足,从而调用过程sleep
放弃处
理机;或者是进程为了与其他进程保持同步而调用
wait
或stop
程序放弃了处理机;或由于执行了exit
texi
调用,终止了当前进程。这几种情况下,由于发生
调度的时机是可以预见的,因此,在这些程序执行
结束之前,都自动调用switch
过程调度其他优先级
高的进程执行。
• 综上所述,UNIX System
Ⅴ
中,发生进程调度的
时机实质上只有两个:一个是进程自动放弃处理机
时自动转入调度进程,另一个则是在由核心态转入
用户态时,系统设置了高优先级就绪进程的强迫调
度标识。
• 3.
调度标识的设置
• UNIX System
Ⅴ
中有三个关于调度和交换用的调
度标识。它们是runrun
、runin
rnuni
和runout
。
• runrun
标识是要求处理机调度程序进行调度的标
识,由唤醒原语wakeup
、setrun
及优先级设置过程
setpri
itsepr
在发现某进程的优先级高于当前进程的优先
级时,设置runrun
标识。另外,每隔一秒一次的时
钟中断处理中也将检查各就绪态进程的优先级而设
置runrun
标识。只要设置了该标识,在中断陷阱程
序结束之前,系统就会调用swtch
过程调度具有最
高优先级的进程执行。
• runin
rnuni
和runout
标识是用于就绪进程换入换出内存
的。runin
rnuni
表示内存无足够空间换入一个外存就绪
态进程,设置runin
rnuni
标识也意味着内存中无适当的
进程可以换出。runout
标识与runin
rnuni
相反,它表示
外存交换区中无适当的进程可以调入内存。
• 4.
调度策略与优先数的计算
• UNIX System
Ⅴ
采用动态优先数调度策略。在
UNIX
系统中,优先数越大优先级越低。调度策略
从内存就绪队列中选取优先数最小的进程投入执行。
• System
Ⅴ采用下式计算各进程的优先数:
PPpri
ipr
=
P-CPU
/2
+
PUSER
+
P-nice
+
NZERO
• 其中,PUSER
和NZERO
是称为基本用户优先数
的阈值。在System
Ⅴ中,这两个数是常数,分别
为25
和20
。P-CPU
为每个进程的最近一次CPU
使
用时间。当进程使用CPU
时,系统每个时钟周期对
该进程的P-CPU
加1
,最多时该值可达80
。另外,
系统按每秒钟的时间间隔对P-CPU
执行除以2
的衰
减操作。这样,如果系统的时钟周期为16.667ms
s16.667m
的
话,则系统进行每秒时钟中断处理时,P-CPU
的
值将由60
变为30
。P-nice
cenPi
是系统允许用户设置的一
个进程优先数偏移值。System
Ⅴ中,P-nice
cenPi
可以被
设置成0 ~ 40
间的一个数。但一旦设置之后,除了
超级用户可以将其减小之外,普通用户仅能作增加
的改变。
• 显然,由于新创建的进程未使用CPU
,其P-CPU
值为0
,因而具有较高的优先级。但随着被调度执
行,其P-CPU
的值将会不断增加,从而在每秒1
次
的时钟中断处理时,将被其他P-CPU
值小的进程
所抢先。然后,随着其他进程的执行以及每秒1
次
的P-CPU
值的衰减,当其优先数小于当前进程和
其他进程之后,又会重新抢占处理机。
• 5.
调度的实现
• 进程调度是由swtch
过程实现的。这里主要讲述
swtch
的执行过程。
• swtch
过程实质上是完成一个进程之间的上下文切
换过程。它的执行分为三个阶段,涉及三个进程。
• 第一阶段检查决定是否做上下文切换和系统是否允
许做上下文切换。如果允许做上下文切换的话,则
保存当前进程的上下文。
• 在UNIX System
Ⅴ
中,系统通过禁止任意的上下
文切换来保证内部数据结构的完整性和一致性。在
做上下文切换之前,系统必须保证各种正在更新的
内部数据结构都已完成,各种队列都已正确链接,
各种数据结构的加锁、解锁都已完成等。
• 在保存了当前进程的上下文之后,紧接着swtch
过
程要先恢复进程0
的进程上下文,以提高优先级和
为第二阶段的调度选择高优先级进程提供执行环境。
在UNIX System
中,当前进程上下文的保存工作主
要涉及各种寄存器内容(寄存器上下文)和栈指针
的保存。因为进程上下文的其他部分都在内存或外
存中,不会因其他进程抢占处理机而受到影响,只
有寄存器只存放当前进程的内容,因此,当一个进
程被抢先时,必须保存各种寄存器的内容以及指向
它们的指针,
以便该进程被再次调度执行时能恢复
其执行环境。
• 当前进程的有关寄存器内容及栈指针的保存是由过
程save(u.u-rsav
)
完成的。该过程把有关寄存器内容
保存在核心栈中或user
erus
结构中的u-rsav
和u-pcb
bpu-中
(此时核心栈在user
erus
结构中)。而进程执行环境的
恢复则是由过程resume
serum
完成的。
• 第二阶段属于进程0
部分。第二阶段使用本节前面
所述的调度算法,从内存就绪队列中寻找一优先级
最高进程。若内存就绪队列中没有这样的进程存
在,则调出idle
iedl
过程循环等待某进程变为就绪状态。
若就绪队列中有符合条件的进程存在,则选取该进
程占据处理机。
• 第三阶段属于被选中进程。该进程已成为当前进
程,因此,它调用resume
serum
,从它的核心栈或user
erus
结
构中的u.u-rsav
及u.u-pcb
bpu.等中恢复该进程的有关寄
存器内容和栈指针,从而使得新进程开始正常执行。
6.4.2
交换
• UNIX
的早期版本(BSD 4.0
以前)在内存和外存
之间传送整个进程,从而给交换赋予了特殊的含义。
即将内存中的整个进程上下文换出内存后将驻留在
外存的整个进程上下文换入内存。
• 交换功能由进程0
完成。在系统初始化结束时,进
程0
就进入无限循环,先试图从外存交换区换入进
程(因为初始化结束时内存总不会是满的),内存
不够时再换出进程。如果没有进程要换入换出时,
则该进程进入睡眠状态。
• 系统通过时钟中断定期唤醒进程0
完成交换功能。
在进程0
执行之前,时钟中断处理程序计算出每个
就绪进程在内存或外存中驻留的时间。
• 交换算法实际上涉及三个部分:外存交换设备的空
间管理、交换区中的进程换入、内存中进程的换出。
sched
scdhe
过程完成进程的换入与换出。至于外存交换
设备的空间管理,将在本章后面部分简单介绍。
• sched
scdhe
过程的流程图如图6.13
所示。
图6.13
sched
scdhe
过程流程图
• 在图6.13
中sched
scdhe
程序首先检查proc
结构表,寻找
一个不在内存且驻留时间最长的就绪态进程。如果
该进程在外存交换区的驻留时间小于2
秒,则表示
没有适当的进程可以换入,从而设置runout
标识后
进入睡眠状态。反之,如果sched
scdhe
过程找到了一个
适当的就绪态进程,则启动输入输出设备,将其写
入内存。如果内存中没有足够的内存空间(这可由
存储表知道),则sched
scdhe
过程按照换出算法寻找在
内存中的进程换出。换出策略是:首先,锁定位已
经锁住的进程不能换出;其次,先换出那些已部分
换出的进程(在正文段被共享时,如果一个进程的
正文段随同该进程被换出了的话,则共享该正文段
的进程变成已部分换出的进程),然后选择睡眠或
暂停状态中优先数最大的,最后选择就绪进程中已
在内存时间最长者。
• 注意,当选择就绪进程换出时,其在内存的驻留时
间不得少于2
秒。如果sched
scdhe
过程在内存中找不到
合适的进程换出,则设置runin
rnuni
标识,表示外存有
进程等待换入,但内存无合适进程换出。在设置了
runin
rnuni
标识后,sched
scdhe
过程调用sleep
过程,进程0
进入睡眠状态。
• 当有合适进程可以换出时,或内存中有足够空间存
在时,sched
scdhe
过程将反复地把所有符合换入条件的
进程换入内存,直到外存交换区不存在可以换入的
进程或内存中没有可以换出的进程时为止。
• 另外,在UNIX System
Ⅴ
中,除了使用sched
scdhe
过程
将内存中的进程换出内存之外,还可以通过一个称
为特别进程0
的进程调用xsched
cxdhse
过程将进程换出。
§6.5
进
程
通
信
• UNIX System
Ⅴ
中的进程通信分为三个部分:低
级通信、管道通信和进程间通信IPC
(interprocess
iseronpctr
communacation
icaoumtnmnac
)。近年来,UNIX System
Ⅴ
的改
进版中又加入了计算机间通信(网络通信)用的
TCP
/IP
协议并提供了相应的系统调用接口。
6.5.1 UNIX
的低级通信
• UNIX
的低级通信主要用来传递进程间的控制信号。
实现传递控制信号的方法有两种。
• 一种是利用睡眠原语sleep
和唤醒原语wakeup
实现
进程间的同步与互斥。sleep
和wakeup
本身不携带
任何信息,比P,V原语操作更低级。sleep
原语
使得当前进程以指定优先数在指定的队列上睡眠,
而wakeup
则唤醒在指定队列上睡眠的所有进程。
• 另一种是利用软中断信号实现同一用户的诸进程之
间的通信。目的是通知对方发生了异步事件。UNIX
System
Ⅴ
中有19
个软中断信号,作用见图6.14
。
• 软中断是对硬件中断的一种模拟,发送软中断就是
向接收进程的proc
结构中的相应项发送图6.14
中的一
个信号。如果用户进程发送的软中断号大于19
,则
接收进程不予理睬,从而发送无效。接收进程在收
到软中断信号后,将按照事先的规定去执行一个软
中断处理程序。但是,软中断处理程序不像硬中断
处理程序那样,收到中断信号后立即被启动,它必
须等到接收进程执行时才能生效。另外,一个进程
自己也可以向自己发送软中断信号,
以便在某些意外
的情况下,进程能转入规定好的处理程序。例如,
大部分陷阱都是由当前进程自己向自己发送一个软
中断信号而立即转入相应处理的。
图6.14 UNIX System
Ⅴ
软中断信号
软中
断号
符
号
名功
能软中断
号
符
号
名功
能
1
SIGHUP
远地用户电话挂断11
SIGSEGV
段违例
2
SIGINT
键盘打入DELETE
键12
SIGSYS
系统调用错
3
SIGQUIT
键盘打入
QUIT
键13
SIGPIPE
PIPE
文件只有写
者无读者
4
SIGILL
非法指令14
SIGALRM
报警信号
5
SIGTRAP
断点或跟踪指令15
SIGTERM
软件终止信号
6
SIGIOT
IOT
指令16
SIGUSR1
用户定义
7
SIGEMT
EMT
指令17
SIGUSR2
用户定义
8
SIGFPE
浮点溢出18
SIGCLD
子进程消亡
9
SIGKILL
要求终止该进程19
SIGPWR
电源失效
10
SIGBUS
总线超时
• 睡眠原语和唤醒原语以及软中断通信是几种非常有
用的进程控制手段。例如,利用sleep
和wakeup
,
可以实现系统中对互斥资源的管理和进程间的同步。
当进程要使用临界资源时,先检测相应的锁定标
志,若锁定标志已置位,则调用sleep
进入睡眠。
直到其他进程退出临界区后释放了锁定标志。如果
系统调用wakeup
唤醒等待该资源的进程,该进程
才有进入临界区的可能。读者可以自行用C
语言或
形式化语言描述出用sleep
和wakeup
实现同步或互
斥的过程。
• 为了给用户进程也提供相应的同步、互斥以及软中
断通信功能,UNIX
系统提供了几种相应的系统调
用和实用程序。一种是用于互斥的实用程序,其格
式是:
lockf
(
fd
,function
,size)
• 其中,fd
是被锁定文件标识,function
是控制值,
可取值:0
,1
,2
,3
。1
表示锁定一个程序段,0
表示不再锁定,而2
则测试和锁定一个程序段,3
则用来测试待锁定的程序段是否已被其他进程锁定。
size
表示自fd
文件的size
个相连字节之后开始锁定程
序段。如果size
等于零,则表示从调用lockf
后开始
锁定。
• 用于同步的系统调用是wait()
或sleep(n)
。其中,
wait()
用于父子进程之间的同步,而sleep
则使得当
前进程睡眠n
秒后自动唤醒自己。
• 系统调用kill(pid,sig
gdkp,)
和signal(sig,func
)
被用来传递
和接收软中断信号。一个用户进程可调用
kill(pid,sig
gdkp,)
向另一个标识号为pid
dpi
的用户进程发送
软中断信号sig
。根据图6.14
可知,用户可以定义的
软中断号是16
或17
。另外,标识号为pid
dpi
的进程通
过signal(sig,func
)
捕捉到信号sig
之后,执行预先约
定的动作func
,从而达到这两个进程的通信目的。
一个经常用到的例子是signal(SIGINT,SIG-IGN)
i()-,
表示当前进程不做任何指定的工作而忽略键盘中断
信号的影响。
6.5.2
进程间通信IPC
• IPC
是UNIX System
Ⅴ
的一个核心程序包,它负
责完成System
Ⅴ进程之间的大量数据传送工作。
在IPC
包被开发出来之前,通信能力一直是UNIX
系统的一个弱点,因为只能利用pipe
来传递大量数
据。而pipe
又存在着只有调用pipe
的进程的子孙后
代才能使用它进行通信的缺点。虽然有名管道能使
非同族进程之间相互通信,但它们不能复用一个有
名管道以便为多对通信进程提供私用通道。也就是
说,有名管道不能识别其通信伙伴,也不能有选择
地接收信息。IPC
核心程序包解决了这些弱点。
• UNIX System
Ⅴ IPC
软件包分三个组成部分:
• (1)
消息(message
)用于进程之间传递分类的格式
化数据。
• (2)
共享存储器(shared memory
seoydhmr )方式可使得不同
进程通过共享彼此的虚拟空间而达到互相对共享区
操作和数据通信的目的。
• (3)
信号量(semaphore
seamphor
)机制用于通信进程之间往
前推进时的同步控制。信号量总是和共享存储器方
式一起使用。
• 由于上述三种方式在UNIX System
Ⅴ中是作为一个
整体实现的,因此,它们具有下述共同性质:
• (1)
每种机制都用两种基本数据结构来描述该机制。
即:
• ①
索引表:
其中一个表项由关键字、访问控制结
构及操作状态信息组成。每个索引表项描述一个通
信实例或通信实例的集合。
• ②
实例表:
一个实例表项描述一个通信实例的有
关特征。例如,消息机制中消息队列表相当于索引
表,而消息头表则相当于实例表,如图6.15
。
• (2)
索引表项中的关键字是一个大于零的整数,它
由用户选择名字。
• (3)
索引表的访问控制结构中含有创建该表项进程
的用户id
和用户组id
。由后述“
control
crolnt
”
类系统调
用,可为用户和同组用户设置读-写-执行许可
权,从而起到通信保护的作用。
• (4)
每种通信机制的“
control
crolnt
”
类系统调用可用来查
询索引表项中的状态,以及置状态信息或从系统中
删除表项。
图6.15
索引表与实例表的关系
• (5)
除了“
control
crolnt
”
类系统调用之外,每种通信机制
还含有一个“
get
tge
”
类系统调用,以创建一个新的索
引表项或者用于获得已建立的索引表项的描述字。
• (6)
每一种索引表项都使用下列公式计算索引表项
的描述字:
• 描述字
=索引表长度×分配序号+索引表项下标
• 例如,如果消息队列表长100
,表项1
的描述字可
以是100
×(分配序号)+1
=1
、101
、201
等。这
样做的好处是,当进程释放了一个旧的索引表项,
且该索引表项又分配给另外的进程时,因为分配序
号的增加将使得描述字改变,从而原来的进程不可
能再次访问该表项。由此,可以起到通信保护作用。
• 其他系统调用访问索引表项时的索引值为描述字
mod
(索引表长度)。
• 下面,简单地介绍三种通信机制的系统调用。
• (1)
消息机制
• 消息机制提供四个系统调用。它们是:
• msgqid
sgdmqi
=
msgget
tsgmge
(key
,msgflg
lsgmf
)
key-t key ;
int
msgflg
lsgmf
;
• msgctl
ltsgmc
(
msgqid
sgdmqi
,cmd
,buf
)
int
msgqid
sgdmqi
,cmd
;
msgqid-ds
#
buf
;
• msgsnd
(
msgqid
sgdmqi
,msgp
,msgsz
szgms
,msgflg
lsgmf
)
int
msgqid
sgdmqi
;
struct
tsruc
msgbuf
*
msgp
;
int
msgsz
szgms
,msgflg
lsgmf
;
• 以及:
•
msgrcv
scgvmr
(
msgqid
sgdmqi
,msgp
,msgsz
szgms
,msgtyp
,msgflg
lsgmf
)
int
msgqid
sgdmqi
;
struct
tsruc
msgbuf
*
msgp
;
int
msgsz
szgms
;
long
msgtyp
;
int
msgflg
lsgmf
;
•
这些系统调用所需要的数据结构和表格都放在头文件
<sys
/types.h>
,<sys
/ipc.h
>
和<sys
/msg.h>
中。因
此,在使用各种通信机制的系统调用之前,必须
include
这三个头文件。
• 系统调用
msgget
tsgmge
返回一个消息描述字
msgqid
sgdmqi
,
msgqid
sgdmqi
指定一个消息队列以便其他三个系统调用使
用。key
和
msgflg
lsgmf
具有获取的语义。key
可以等于
关键字IPC-PRIVATE
,以保证返回一个未用的空
表项,key
还可以被设置成一个还不存在表项描述
字的表项号。这时,只要mshflg
lsghmf
&IPC-CREAT
为
真,则系统会生成一个新的表项并返回描述字。例
如,
msgqid
sgdmqi
=
msgget
tsgmge
(MSGKEY
,0777) ;
• 在MSGKEY
SEYKMG
所对应的消息队列表项不存在时,将
创建该表项,在MSGKEY
SEYKMG
所对应的表项存在时,
msgget
tsgmge
返回该表项的描述字。
• 系统调用msgctl
ltsgmc
用来设置和返回与msgqid
sgdmqi
相关联的
参数选择项,以及用来删除消息描述符的选择项。
cmd
的取值范围为{IPC-STAT ,IPC-SET,IPC-
RMID}
。其中,IPC-SET
表示将指针为buf
中的用
户id
等读入与msgqid
sgdmqi
相关联的消息队列表项中;
IPC-STAT
ISPTACT
表示将与msgqid
sgdmqi
相关的消息队列表项中
所有当前值读入buf
所指的用户结构中;而IPCIPCRMID
则表示msgctl
ltsgmc
调用删除msgqid
sgdmqi
所对应的消息
队列表项。buf
是用户空间中用于设置或读取消息
队列状态的索引结构指针。
• 系统调用msgsnd
和msgrcv
scgvmr
则分别表示发送和接收
一消息。msgsnd(msgqid,msgp,msgsz,msgflg
lszgdnmmfspq,)
中的
msgqid
sgdmqi
是msgget
tsgmge
返回的消息队列描述符;msgp
则
是用户消息缓冲区指针;msgsz
szgms
是消息正文的长
度;而msgflg
lsgmf
则是同步标识,规定msgsnd
发送消息
时,是发送完毕后返回还是不等发送完毕立即返回
(此时msgflg
lsgmf
&IPC-NOWAIT
IPTCNOWA
为真)。
• 系统调用msgrev
segvmr
中比msgsnd
多一个参数msgtyp
,
它规定接收消息的类型。msgtyp
=0
时,
表示接收与
msgqid
sgdmqi
相关联的消息队列上的第一个消息;msgtyp
>0
时,表示接收与msgqid
sgdmqi
相关联的消息队列上
msgtyp
类型的第一个消息;而msgtyp
<0
时,则表
示接收小于或等于msgtyp
绝对值的最低类型的第一
个消息。另外,msgflg
lsgmf
指示当与msgqid
sgdmqi
相关联的消
息队列上无消息时系统应当怎么办。
• 例如,图6.16
和图6.17
分别给出了用C
语言编写的,
由顾客进程和服务者进程调用的程序例子。
#include
〈sys
/types.h
〉
#include
〈sys
/ipc.h
〉
#include
〈sys
/msg.h
〉
#define MSGKEY 75
strucu
msgform
{
long
mtype
;
char
mtext
[256
]
;
};
main ( )
{
struct
msgform
msg
;
int
msgqid
,pid
,*
pint ;
msgqid
=
msgget
(MSGKEY
,0777) ;
/
*
建立消息队列*
/
pid
=
getpid
( ) ;
pint = (
int
*
)
msg.mtext
;
*
pint =
pid
;
msg.mtype
= 1 ;
/
*
指定消息类型*
/
msgsnd(msgqid,&msg,sizeof(int),0); /
*
往msgqid
发送消息msg
*
/
msgrcv(msgqid,&msg,256,pid,0) ; /
*
接收来自服务进程的消息*
/
printf("client
: receive from
pid%d
\n"
,*
pint) ;
}
图6.16
顾客进程的程序段
#include
〈sys
/types.h
〉
#include
〈sys
/ipc.h
〉
#include
〈sys
/msg.h
〉
#define MSGKEY 75
struct
msgform
{
long
mtype
;
char
mtext
[256
]
;
}
msg
;
int
msgqid
;
main ( )
{
int
i
,pid
,*
pint ;
extern cleanup ( ) ;
for (i=0 ; i<20 ; i++) /
*
软中断处理*
/
signal (i
,cleanup) ;
msgqid
=
msgget
(MSGKEY
,0777
|
IPC-CREAT) ; /
*
建
立与顾客进程相同的消息队列*
/
for (; ;)
{
msgrcv
(
msgqid
,&
msg
,256
,1
,0) ; /
*
接收来自
顾客进程的消息
*
/
pint = (
int
*
)
msg.mtext
;
pid
=
*
pint ;
printf
("server : receive from
pid
%d
\n"
,pid
) ;
msg.mtype
=
pid
;
*
pint =
getpid
() ;
msgsnd
(
msgqid
,&
msg
,sizeof(int
)
,0);/
*
发送应答消
息*
/
}
}
cleanup ()
{
msgctl
(
msgqid
,IPC-RMID
,0) ;
exit () ;
}
图6.17
服务者进程的程序段
• 图6.16
是顾客进程。该进程向服务者进程发送一个
含有进程号pid
dpi
以及类型为1
的消息,向服务者进
程发出服务请求。然后,从服务者进程接收相应的
回答或服务。
• 在图6.17
中,MSGKEY
SEYKMG
是用户自己定义的关键字,
已在本节前面部分做过说明。而msgform
则是用户
自定义的发送消息正文和消息类型,这一消息被定
义为256
字节长。紧接着,顾客进程首先使用系统
调用msgget
tsgmge
创建,或得到与关键字MSGKEY
SEYKMG
相关
联的消息队列描述字msgqid
sgdmqi
,并由库函数getpid
tgdpei
()
得到该进程ID
。接下去是对消息正文做类型转换,
以便计算消息长度并将进程ID
复制到消息正文中。
最后,顾客进程调用msgsnd
把消息msg
挂入以
msgqid
sgdmqi
为描述字的消息队列,并从该队列接收服务
进程发往该进程的第一个消息(用进程号pid
dpi
作消
息类型)。
• 图6.17
是服务者进程。该进程首先检查是否捕捉到
由kill
lki
发来的软中断信号。如果捕捉到时,则调用
函数cleanup
从系统中删除以msgqid
sgdmqi
为描述字的消
息队列。如果它捕捉不到软中断信号或者接收的是
不能捕捉的SIGKILL(9)
信号,则该消息队列继续
保留在系统中,而且在该队列被删除以前试图以该
关键字建立新消息队列的尝试都会失败。
• 然后,服务者进程使用系统调用msgget
tsgmge
,并在
msgget
tsgmge
中置位IPC_CREAT
来建立一个消息队列结
构。紧接着,服务者进程接收所有类型为1
的,也
就是从顾客进程来的请求消息。这是由系统调用
msgrcv
scgvmr
完成的。在接收到消息之后,服务者进程从
消息中读出顾客进程的ID
,并将返回的消息类型置
为顾客进程的ID
。
• 然后,服务者进程把要发送的消息复制到消息正文
域中,并使用msgsnd
将消息挂入msgqid
sgdmqi
为描述字
的消息队列。本例中,由服务者进程发送给顾客进
程的消息也是服务者进程的ID
。
• 在消息机制中,消息被格式化为类型与数据对,且
允许不同的进程根据不同的消息类型进行接收,这
是使用管道通信所无法办到的。
• (2)
共享存储区机制
• 进程能够通过共享虚拟地址空间的若干部分,然后
对存储在共享存储区中的数据进行读和写来直接地
彼此通信。操纵共享存储区的系统调用类似于消息
机制,共有4
个系统调用。它们是:
• ①
建立新的共享区或返回一个已存在的共享存储
区描述字的shmget(key,size,
flag
)
。其中,key
是
用户指定的共享区号,size
是共享存储区的长度,
而flag
则与msgget
tsgmge
中的msgflg
lsgmf
含义相同。
• ②
将物理共享区附接到进程虚拟地址空间的调用
shmat(shmid,addr,flag
)
。其中,shmid
isdhm
是shmget
tsghem
返
回的共享区描述字,而addr
是将共享区附接到其上
的用户虚拟地址,当addr
等于零时,系统自动选择
适当地址进行附接(默认)。flag
规定对此区是否
是只读的,以及核心是否应对用户规定的地址作舍
入操作。shmat
sahtm
返回系统附接该共享区后的虚拟地
址。
• ③
进程从其虚拟地址空间断接一个共享存储区的
系统调用shmdt(addr
)
。其中,addr
是shmat
sahtm
返回
的虚拟地址。
• ④
查询及设置一个共享存储区状态和有关参数的
系统调用shmctl(shmid,cmd,buf
)
。其中,shmid
isdhm
是
共享存储区的描述字,cmd
规定操作类型,而buf
则是用户数据结构的地址,这个用户数据结构中含
有该共享存储区的状态信息。
• 用户可以使用上述4
个系统调用为通信进程建立、
附接以及断接共享存储区。共享存储区的好处在于
为通信进程提供了直接通信的手段,使得通信进程
可以直接访问彼此的某些虚拟空间。
• 图6.18
给出两进程共享存储区的示意图。
图6.18
共享存储区示意图
• 一个共享存储区建立后可以被附接到一个进程的多
个虚拟区间上,而一个进程的虚拟空间也可以附接
多个共享存储区。
• 需要指出的是,共享存储区机制只为通信进程提供
了访问共享存储区的操作条件,而对通信的同步控
制则要依靠后述的信号量机制等才能完成。
• 图6.19
和图6.20
分别给出了将进程附接到共享存储
区上,以及进程间共享存储区的C
语言程序实例。
• 在图6.19
中,该进程建立了16K
字节的共享存储
区,并将存储区附接到了虚拟地址addr
上。然后,
从该存储区的起始单元开始,顺序写入0
到255
个
自然数。如果该进程捕捉到一个软中断信号
(SIGKILL
除外),则由系统调用shmctl
ltschm
删除该
共享区。
#include
〈sys
/types.h
〉
#include
〈sys
/ipc.h
〉
#include
〈sys
/shm.h
〉
#define SHMKEY
75
#define K
1024
int
shmid
;
main ( )
{
int
i
,*
pint ;
char
*
addr
;
extern char
*
shmat
( ) ;
extern cleanup ( ) ;
for (i=0 ; i<20 ; i++) /
*
软中断处理
*
/
signal (i
,cleanup) ;
shmid
=
shmget
(SHMKEY
,16
*
K
,0777
|IPC-CREAT) ;
/
*
建立16K
共享区SHMKEY
*
/
addr
=
shmat
(
shmid
,0
,0) ; /
*
共享区首地址
*
/
printf
("
addr
0x%x
\n"
,addr
) ;
pint = (
int
*
)
addr
;
for (i=0 ; i<256 ; i++)
*
pint++ = i ;
pint = (
int
*
)
addr
; /
*
共享区第一个字中写入长度256
,以便
接收进程读*
/
*
pint = 256 ;
pause ( ) ; /
*
等待接收进程读
*
/
}
cleanup ( )
{
shmctl
(
shmid
,IPC-RMID
,0) ;
exit ( ) ;
}
图6.19
共享存储区程序实例
#include
〈sys
/types.h
〉
#include
〈sys
/ipc.h
〉
#include
〈sys
/shm.h
〉
#define SHMKEY
75
#define K
1024
int
shmid
;
main ( )
{
int
i
,*
pint ;
char
*
addr
;
extern char
*
shmat
( ) ;
shmid
=
shmget(SHMKEY
,8
*
K
,0777); /
*
取共享区
SHMKEY
的id
*
/
addr
=
shmat
(
shmid
,0
,0) ; /
*
连接共享区*
/
pint = (
int
*
)
addr
;
while (
*
pint==0); /
*
共享区的第一个字节为零时,等待*
/
for (i=0 ; i<256 ;
*
pint++) /
*
打印共享区中内容*
/
printf
("%d
\n" .
*
pint++) ;
}
图6.20
共享存储区程序实例
• 在图6.20
中,另一个进程附接到与关键字SHMKEY
SEYKMH
相关联的存储区上。也就是与图6.19
所述的同一个
存储区上。为了表明每个进程可以附接一个共享存
储区的不同总量,图6.20
中只取该存储区的8K
字节。
该进程等待着直到图6.19
中进程在共享存储区中的
第一个字节写入一个非零值后读出该存储区;此时
图6.19
进程暂停以使图6.20
进程执行读出打印操作。
• (3)
信号量机制
• 信号量机制是基于第3
章所述的P、V原语原理的。
System
Ⅴ中一个信号量由以下几部分组成:
• ①
信号量的值,一个大于、小于或等于零的整数。
• ②
最后一个操纵信号量的进程的进程id
。
• ③
等待着信号量值增加的进程数。
• ④
等待着信号量值等于零的进程数。
• 信号量机制提供下列系统调用对信号量进行创建、
控制、以及P、V操作。它们是:
• ①
用于产生一个信号量数组以及得以存取它们的
系统调用semget(semkey
tsegykmee
,count,flag)
。其中,
semkey
seykme
和flag
类似于建立消息和共享存储区时的这
些参数。semkey
seykme
是用户指定的关键字,count
规定
信号量数组的长度(如图6.21
所示),flag
为操作
标识。semget
tsegme
用来创建信号量数组或查找已创建信
号量数组的描述字。例如:
semid
=
semget
tsegme
(SEMKEY
,2
,0777
|IPC-CREAT) ;
• 创建一个关键字为SEMKEY
SEYKME
的含有两个元素的信号量
数组。
图6.21
信号量数组
• ②
用于P、V操作的系统调用semop
(
semid
,
oplist
itsopl
,
count)
。其中,semid
是semget
tsegme
返回的描述字,oplist
itsopl
是用户提供的操作数组的指针,count
是该数组的大
小。semop
返回在该组操作中最后被操作的信号量在
操作完成前的值。
• 用户定义的操作数组中的每个元素包含三个内容,
它们是信号量序号、操作内容(对信号量进行P操
作或V操作的值)、标识。一个数组可同时包含对
n
(n
>1
)个信号量的操作。
• semop
根据操作数组所规定的操作内容改变信号量
的值。如果操作内容为正数(V操作),则它将该
信号量增加该操作内容的值,并唤醒所有等待此信
号量值增加的进程。如果操作内容为零,则semop
检查信号量的值,若为零,semop
执行对同一操作
数组中其他信号量的操作;否则,废弃本次系统调
用所完成的所有信号量操作之后,调用sleep
使该
进程进入睡眠状态。如果操作内容是负数且绝对值
小于等于信号量值,则semop
从信号量值中减去操
作内容;否则,调用sleep
让该进程睡眠在等待信
号量值增加的事件上。例如:
struct
sembuf
{
unsigned short
sem
-num ;
shor
sem
-op ;
short
sem-flg
;
}
Psembuf
;
semid
=
semget
(SEMKEY
,2
,0777) ;
Psembuf.sem
-num = first ;
Psembuf.sem
-op = -1 ;
Psembuf.sem-flg
= SEM-UNDO ;
semop
(
semid
,&
psembuf
,1) ;
• 定义了一个对二元信号量数组中第一个信号量的P
操作。其中,SEM-UNDO
SDNUOME
是为了保证P操作的原
子性而设置的标识。
• ③
对信号量进行控制操作的系统调用semctl(semid
,
number,
cmd,arg
cgdm,)
。其中,semid
是semget
tsegme
返回的
信号量的描述字,number
rbneum
是对应于semid
的信号量
数组的序号,cmd
是控制操作命令,arg
是控制操
作参数,是一个union
结构:
union
semun
{
int
val
;
struct
semid-ds
*
buf
;
unsigned short
*
array ;
}
arg
;
• 系统根据cmd
的值解释arg
,并完成对信号量的删
除、设置或读信号量的值等操作。有关semctl
的操
作命令,由于较多和比较复杂,这里不再深入讨论。
• 上面介绍了有关IPC
的三种通信机制。这三种机制
使用消息和共享存储区方式使多个进程使用同一介
质(消息队列或共享存储区)进行通信。这优于管
道等通信方式。但是,由于各系统调用中使用的关
键字的语义很难扩展到一个网络上(不同的机器上
同一关键字可以描述不同的对象),因此,IPC
仍
是属于单一机器环境下的通信机构。
§6.6 UNIX
存储管理
• 如前所述,存储管理极大地影响进程调度和控制,
因为调度程序不调度一个只有proc
结构在内存的进
程执行。然而,内存是一种有限的资源,无法容下
全部活动进程。存储管理系统必须决定哪个进程的
哪个部分应该放在内存,并管理那些不在内存又属
于同一进程虚空间的部分。因此,UNIX
系统必须
解决为进程分配内存空间、进行内存扩充、以及完
成由虚存到物理存储器的地址变换,和内存信息保
护与共享等问题。
• UNIX System
Ⅴ
采用请求调页和交换策略进行存
储器管理。早期的UNIX
系统只采用交换技术进行
主存扩充。交换技术与请求调页策略的主要区别在
于:交换技术换进换出整个进程(proc
结构和共享
正文段除外),因此,一个进程的大小受物理存储
器的限制;而请求调页策略在内存和外存之间来回
传递的是存储页而不是整个进程,从而使得进程的
地址映射具有了更大的灵活性,且允许进程的大小
比可用物理存储空间大得多。
• 在本章前面有关UNIX
进程调度部分,已对UNIX
系
统的交换策略作了介绍。这里,主要介绍请求调页
策略时的存储管理技术。
6.6.1
虚存空间划分和管理思想
• 内存管理是基于一定的硬件基础的,本节以VAXVAX-
11
机为例,说明System
Ⅴ的地址空间划分和存储
管理的基本思想。
• 在VAX-11
中,虚存空间被画分为4
个功能段:即进
程空间的程序段P
0
、控制段P
1
、系统空间的核心区
和保留区。每个区的动态扩展方向如图6.22
中箭头
所示。这里,整个虚存空间的寻址范围为(0~2
02~
32
-
1
)。
• 每个区都有自己的页表。每个页表的长度和起始地
址分别由相应的长度寄存器和基址寄存器描述。
图6.22 VAX-11
机虚存空间画分
• 另外,除了以功能分区以外,VAX-11
的地址空间
又被画分成以512
字节为1
页的线性数组,页的编
码范围为(0~2
02~
23
-1
),如图6.23
所示。
31
9
0
图6.23 VAX-11
机虚拟地址构成
• 与此相对应,VAX-11
的物理存储器也被分成了512
字节为一个页面的线性数组。页面的编码范围为
(0~2
02~
21
-1
),如图6.24
所示。在图6.23
的虚拟地址
结构中,高两位,也就是30
位和31
位是用作区分功
能区的,例如00
表示该页在P
0
区,而01
表示该页在
P
1
区,而10
则表示该页在系统区。
虚页号 字节偏移量
VPN
31 30 29
9
0
图6.24 VAX-11
机的内存地址构成
• 由虚存地址到物理地址的变换通过页表和寄存器等
组成的硬件地址变换机构完成。页表项的内容如图
6.25
所示。
31 30 27 26 25 21 20 0
图6.25
页表项内容
页面号 字节偏移量
PFN
物理页面号PFN
M
V
• 其中,第31
位(最高位)是有效位,如果该位
(V)=1
,则表示该虚页所对应的内容在内存中,且
第0~
第20
位所对应的是该虚页的页面号。V=0
时,
则该虚页不在内存,硬件将产生相应的出错信息并
转由操作系统处理。
• 第30
位至27
位是保护位,它们指明不同的处理机访
问模式下,对该页面的读写操作权。
• 第26
位M
是修改位,在内存中,第一次对该页面进
行写操作修改该页面内容后,要将该位置1
,以便
将其换出时写回磁盘保存最新信息。如果M=0
,
则由于磁盘上保存有该页副本,从而换出时不必写
回外存而减少不必要的I
/O
操作。
• 另外,有的系统中还设置有访问位R
和年龄位A
等。
其中R
指示最近是否有进程访问过该页,而A
则记
录该页在内存中驻留的时间。R
和A
都是用于请求
调页算法的,后面将进一步介绍。
• 在VAX-11
中,UNIX System
Ⅴ
把核心正文段、核
心数据段以及页表全部放入核心区,
并在系统初始
化时使其常驻内存的低地址部分。核心区虚拟地址
空间与物理空间的对应关系如图6.26
。
• 核心页表和诸进程页表在物理上是一块连续区。这
些页表覆盖整个物理空间。
• 核心页表的起始地址和长度分别存放在称为特权寄
存器的SBR
和SLR
中,它们在操作系统被引导启
动时由引导程序写入。
图6.26
系统虚空间及内存空间布局
• 与核心页表相对应,每个进程的P
0
区和P
1
区也有自
己的页表。正如图6.26
所示的那样,各进程页表都
在核心虚存空间分得一段连续的虚存区。由于核心
虚存空间被所有用户进程共享,所以两不同进程的
页表不能有相同的虚存地址。这也正如在段页式管
理中每个段必须有唯一的段名一样。
• 当前执行进程的P
0
区和P
1
区的页表虚存始址存放在
相应的基址寄存器P
0
BR
,P
1
BR
和页表长度寄存器
P
0
LR
,P
1
LR
中。核心页表和进程各区页表在内存
中的逻辑关系如图6.27
所示。
• 当前执行进程的P
0
BR
,P
1
BR
,P
0
LR
和P
1
LR
的内
容在进程调度发生进程上下文切换时装入。显然,
在进程空间地址变换时,为了得到进程页表所指的
实际物理地址,CPU
至少得访问存储器两次。
图6.27
内存中核心页表与进程页表的逻辑关系
• UNIX System
Ⅴ对内存中的页表区和P
0
区与P
1
区采
用了不同的分配释放方法。对于页表区,核心采用
的是分区式管理中的最先适应算法(first fit
iftsrf
);而
对于与P
0
区和P
1
区对应的内存高地址部分,核心采
用的是位示图分配算法和请求调页方法。
• 下面进一步讨论System
Ⅴ的内存分配与释放、地
址变换及内存扩充等问题。
6.6.2 UNIX System
Ⅴ
的内存分配与释放
• UNIX
系统中的进程是由父进程根据需要动态生成的,每个
进程都享有自己的虚拟空间。所以,在生成一个子进程
时,系统为该子进程建立自己的虚拟空间。具体地说,就
是为子进程分配页表项(包括P
0
区、P
1
区的页表以及核心页
表中的页表项)并使之与系统虚拟空间相对应。然后,再
为子进程分配内存页面存放P
0
区和P
1
区的程序和数据代码。
• 从而,内存空间的分配实际上变成了两个问题,即:
• (1) P
0
区和P
1
区页表的分配和得到在核心虚拟地址空间的始
址dspt
。
• (2) P
0
区和P
1
区所需内存分配并得到相应的页面号。
• 与此相对应,内存的释放也变成了进程P
0
区与P
1
区页表的释
放以及进程P
0
区与P
1
区的释放问题。
• 1.
进程页表的分配与释放
• 在UNIX System
Ⅴ中,页表区的分配使用了分区式
管理的最先适应分配算法。这是因为整个进程页表
区在核心虚拟地址空间和内存中是连续的,而且进
程页表常驻内存,变化较少,使用最先适应算法既
可满足系统管理的需要,又有较少的系统开销。
• 进程页表的分配与释放主要由4
个过程完成(不包
括内存初始化过程),它们是malloc
,mfree
,
sptalloc
和sptfree
fserpt
。其中sptalloc
和sptfree
fserpt
分别调用
malloc
和mfree
,因此,可以说进程页表的分配释
放主要由malloc
和mfree
完成。
• malloc
的原理可简述如下(请参照第5
章分区式管
理中的有关部分):
• 系统内页表区按空闲区的地址,从低到高成一个自
由链式分区可用表map
。其中每个表项包含两个元
素,一个是该空闲区的页面数(
或者是可登记项的
项数)size
,另一个是空闲区页表在核心页表表项中
所对应的索引脚标addr
。显然,由索引脚标addr
,
可以得到该页表对应的系统虚存空间始址dspt
。
• 以自由链map
的头指针mp
和所要求的页面数或表
项数size
作输入参数,在map
中一旦搜索到一个大
于或等于size
的空闲页表区,则将它分配给所要求
进程和调整自由链,然后再返回索引脚标addr
。
• 以上就是malloc
的原理。除了用于内存页表区分配
之外,malloc
还适用于交换区的分配。
• mfree
的原理可简述如下(
请参考第5
章分区释放与
合并部分):
• 对于所要释放页表的大小size
及起始号a
,从map
链
的头指针出发,按起始号大小插入链中相应的位置。
如果所释放的页表区前后有空闲区存在的话,则进
行相应的合并(
合并方法参见第5
章)
后再调整map
链
并返回。
• 同理,mfree
也用来进行交换区等释放空闲区处理。
• 2. P
0
区与P
1
区的内存分配与释放
• 在系统空间及在内存的相应区中,有一个内存位示
图。该位示图就是用来进行各进程的进程区内存分
配与释放管理的。位示图的每一位表示一个物理页
面的使用情况,当对应页面已被分配时,该位为
1
,否则为0
。位示图的大小由内存的大小和页面的
大小所决定,一个容量为16M
和每页512
字的内存
将有一个4K
字节大小的位示图。显然,对于核心
区那些常驻内存的固定部分,其位示图的对应位也
是固定的,因而可以不要地址变换机构。在System
Ⅴ中,位示图所对应的内存首地址是memvad
。
• 由于位示图一般具有几K
字节,而在进程执行期
间,页面的更换又相当频繁,如果每次页面更换都
必须扫描整个位示图,则显然会大大影响执行效率。
为此,系统设置了一个长度为100
的mem
结构,以
减少扫描位示图的次数。该结构包含下列元素:
struct
{
int
m-free; /
*
空闲页面数,P-num
中存有页面号的最大下标
*
/
int
m-lo;
/
*
最低页面号
*
/
int
m-hi;
/
*
最高页面号
*
/
int
m-ptr
;
/
*
上次查找memvad
结束时的指针
*
/
int
m-avail;
/
*
内存中的空闲页面数
*
/
short
m-pnum
[NICMEM
];
/
*
记录本组空闲页面号,最
多NICMEM=100
个
*
/
}
mem
;
• 用于内存管理的函数有二个:即memall
leaml
和memfree
。
内存页面的分配由memall
leaml
完成,而内存页面的释放
则由memfree
完成。memall
leaml
和memfree
二者都使用
上述数据结构进行页面分配和释放。
• memall
leaml
的调用形式为:memall(base,size
ezabmslas
)
。其中,
base
ebas
为欲填入页面号的页表始址,而size
是申请分
配的内存页面数。
• memall
leaml
首先判别m-avail
l-,看内存中有无足够的页
面,若没有则返回零值。否则,它直接从m-pnum
中取出size
个空闲页面,
并把memvad
表中相应位
置成已分配标识。然后,从m-avail
l-中减去已分配的
页面数和修改m-free
。如果在m-pnum
数组中存放
的100
个空闲页面号都已分配完,则系统扫描
memvad
,从中找出未分配的页面号填入m-pnum
中,然后再分配,从memvad
表中查找未分配的页
面号不是每次都从头开始,
而是从m-ptr
rpmt
指出的当
前位置开始向后查找。当到达内存最后一个页面mmhi
时,再从第一个页面m-lo
开始重新分配。每分配
一个页面,便把相应的页面号填入base
ebas
所指出的页
表中。最后,返回实际分到的页面数。
• 内存页面的释放由memfree
完成,其调用形式为:
memfree(base,size
ferzbmsas
)
。其中,base
ebas
为释放内存页面的
页表始址,size
为所释放的页面数。memfree
从base
ebas
所指页表中取出size
个页面号,并将memvad
中对应
位置为空闲标识。若m-pnum
不满100
项的话,
memfree
就把所释放的页面号按从低到高的顺序放
入m-pnum
中,否则不作处理。
6.6.3
地址变换
• 对应于6.6.1
节中所述UNIX System
tIeNUXmSys
Ⅴ空间画分,
VAX-11
机中有二种地址变换方法。一种是将虚存
空间的核心区地址变换到内存的低地址部分,另一
种将虚存空间的进程空间(P0
区和P1
区)
变换到内存
的较高地址部分,首先介绍核心区的地址变换。
• 1.
核心区地址变换
• 页式管理的基本地址变换过程由以下几步组成:
• (1)
装配页表基址寄存器SBR
SRB
和长度寄存器SLR
SRL
。
• (2)
把虚拟地址中的虚页号和SBR
SRB
的内容相加得到
相应的页表项
• (3)
将页表项中所对应的内存页面号与页内偏移值
相加,得到所要访问的物理地址。
• 以上各步由硬件自动完成。
• 在VAX-11
机中,SBR
SRB
和SLR
SRL
的内容由引导程序在
系统初启时自动装入,SBR
SRB
存放核心页表的起始物
理地址,且核心页表在内存中是连续存放的。因
此,核心区的地址变换可以按第5
章所述地址变换
步骤由硬件自动实现。
• 考虑到内存保护等功能之后的核心区地址变换过程
如图6.28
所示。
图6.28
核心区地址变换
• 2.
进程空间地址变换过程
• 进程空间(
包括P
0
区和P
1
区)
的地址变换过程比核心
区的地址变换过程复杂。这是因为当一个进程被调
度选中占据处理机时,由于用户进程无法直接访问
存在于核心区的页表起始地址,因此,进程上下文
切换只能在寄存器P
0
BR
和P
1
BR
中装入进程页表在
核心区的虚拟地址。因此,硬件必须首先使用核心
页表计算出进程页表的物理地址,然后再由进程页
表计算出需要访问的物理地址。显然,进程空间的
地址变换至少要比核心区的地址变换多访问一次内
存,从而引起访问速度的下降。为了解决这个问
题,VAX-11
中设置了相应的地址转换块表以保存
那些经常使用的页表项副本。
6.6.4
请求调页技术
• 当页表有效位V=0
时,由有效位定义可知,进程所
要访问的页不在内存中。当所访问的页不在内存
时,该页只能在下述三种介质的任一种之中:
(1)
在外存交换区中,
(2)
在外存可执行文件中,
(3)
在输入输出缓冲区的空闲队列中,针对这三种不同
的情况,系统除了要在内存中分配或淘汰相应的页
面以调入这些页之外,还要正确区分这些页所在的
位置,以便迅速地将所需要的页调入内存。
• 为了区分缺页所在的位置,系统设置了与页表表项
相对应的磁盘块描述项和页面数据表。
• 磁盘块描述项(disk block descriptors)
由设备号、块
号及磁盘块类型等栏目组成。这里,假定在外存中
每块的长度等于内存每个页面的长度。每一个磁盘
块描述项与一个页表表项相对应,它描述一个页的
磁盘拷贝。磁盘块描述项中的设备号指出该页的磁
盘拷贝所在的设备号,而块号则指明在该设备的哪
一块上。类型是指明该块属于可执行文件还是属于
交换区。磁盘块描述项如图6.29
所示。
图6.29
磁盘块描述项
(
交换区,可执行文件等)
设备号块号类型
• 页面数据表(page
fram
data
table)pfdata
teadpbfalt
描述每个
物理页的状态、引用该页的进程个数及该页副本所
在的逻辑设备号和块号等。每一个pfdata
adpfat
项与一个
页表表项相对应。pfdata
adpfat
各项所含内容如图6.30
所
示。其中,页状态指示该页是在交换设备上还是在
可执行文件中,并指示该页是否正在被读写以及该
页是否可被重新分配等。逻辑设备号和块号指示该
页的副本所在位置。队列指针则把该pfdata
adpfat
描述项
链接到一个相应的空闲页面链表上。空闲页面链表
是页的缓冲池,其中的页面可被重新分配。如果进
程在某个地址上出现缺页,则它可能不必启动外存
就可在空闲页面链表中找到相应的页并将其读入内
存,从而减少不必要的输入输出操作。
图6.30
pfdata
adpfat
描述项
• 核心按最近最少使用算法把页面上的数据写入缓冲
池中,在它把一个缓冲区分配给某个页面之后,只
要不是所有其他缓冲池都在更近的时间内使用过
了,就不能让另一页面占用该缓冲池。这样做的好
处就是保证刚被访问过的页面不会马上从缓冲池写
入外存。页表项、磁盘块描述项、pfdata
adpfat
项及内存
物理页面的关系如图6.31
。
逻辑设备号队列指针其他
与块号
引用该页
的进程数
页面号页状态
图6.31
请求调页用数据结构间的关系
• 利用上述几种数据结构,可将请求调页时基本处理
过程描述如下:
• 当V=0
,即发生缺页时,核心先检查空闲页面链表。
如果空闲页面链表中存在一个对应的pfdata
adpfat
表项,
该表项中所含逻辑设备号与块号与所需要调入页的
逻辑设备号及块号相同(
可由磁盘块描述项得到)
,
则不必启动交换设备或文件系统,而直接从空闲页
面链表中移出该页即可。图6.32
给出了该调入过程
的流程图。
图6.32
请求调页的调入基本处理过程
• 例
当进程访问虚拟地址1493K
时,页表项中有效位V=0
,从
而发生缺页。此时,由磁盘块描述项得到该虚拟地址
(1493K)
所对应的外存页面在逻辑设备号为1
,块号为2743
处;且由页表项可知,在该页换出内存前所对应的内存页
面号为794(
参见图6.31)
。然后,由图6.32
中处理流程,首先
根据页面号794
检查空闲页面链表,找到一个相应的pfdata
项。其中逻辑设备号为1
且块号为2743
,即页面794
中的数
据或程序还在缓冲池中而未写到外存。从而只需从缓冲池
中把794
号页移到内存而不必启动外部设备。
• 上述过程只是请求调页中的调入过程。如果内存中已无足
够的页面存放调入页,显然,系统必须淘汰相应的内存页
面以存放刚调入的页。对于UNIX System
Ⅴ的不同实现,淘
汰策略不相同,这里介绍一种使用年龄位实现的最不经常
使用页面淘汰算法。
• 最不经常使用算法需要在页表项中增设一年龄位A
。
从该页进入内存时开始,系统定时检查该页是否被
访问过,如果该页在一个检查周期内被访问过,则
将其年龄位置0
,否则,系统每检查一次年龄位增1
。
当年龄位大于某个阈值n
时,则该页被设置成可以
换出的而被放入空闲页面链表。其淘汰原理如图
6.33
所示。
• 另外,为了减少抖动问题,System
Ⅴ在发现缺页
时,总是锁住发生缺页的那个区,从而防止将发生
缺页的部分或即将执行的部分换出内存。
图6.33
最不经常使用淘汰原理
本
章
小
结
• 本章从UNIX System
tIeNUXmSys
Ⅴ中进程的概念出发,介绍了
UNIX
中进程动、静两方面特性以及描述方法,
然
后,介绍了UNIX System
tIeNUXmSys
Ⅴ的进程创建、调度、执
行和撤消等的控制手段、方法以及相应的用户接口,
除此之外,还讨论了UNIX System
tIeNUXmSys
Ⅴ的进程通信部
分,包括用于同步与互斥等控制用的低级通信以及
大量传递信息的IPC
机制。最后,介绍了与进程管
理息息相关的存储管理部分。
• 对于进程的概念来说,本章重点强调了进程是在进
程上下文中执行这个概念。为了深入掌握这一概
念,首先必须对什么是进程上下文有一个清楚的认
识。本章重点介绍了进程上下文的各个组成部分以
及进程上下文的切换方法。
• 除了进程0
之外,UNIX
的所有进程都是由父进程创
建生成。在父进程创建生成子进程时,系统要为子
进程生成自己的上下文,这就需要调用6.6
节所述
存储管理程序为其分配proc
结构、核心页表、进程
页表以及user
erus
结构等。从而,如果内存中无足够的
空间或proc
结构已经用完,则无法生成子进程。在
子进程创建成功之后,马上就看到了子进程和父进
程并发执行,
抢占处理机的现象。至于谁先抢得处
理机,要依靠调度程序决定。UNIX System
Ⅴ
的调度策略是基于优先级的,即选取优先级最高者
(
优先数最小者)
占据处理机。但是,优先级的计算
又是与时间片有关的。因此,UNIX
的调度是基于
优先级加时间片的。
• 另外,UNIX
系统没有作业的概念,用户必须在一
个进程的控制之下和系统进行会话,所输入的数据
也必须先送到内存工作区之后,
再由进程决定是否
写入外存文件系统保存。UNIX
的交换程序虽有中
级调度(
占据内存)
的概念,但它只不过是为了内存
扩充而进行,
把暂不执行的进程换出内存和把将要
执行的进程换入内存的工作。
• 进程通信一直是UNIX
系统较弱的一部分,但IPC
机构弥补了这一点。UNIX System
tIeNUXmSys
Ⅴ的IPC
提供了
消息、信号量及共享存储区等大量信息传递方法。
不过,IPC
机构只能在一台机器内使用,不能扩展
到网络通信上去,这是它最大的弱点。
• UNIX System
tIeNUXmSys
Ⅴ的存储管理策略是交换和请求调页
相结合。交换算法在内存与外存交换区之间交换整
个进程。而请求调页系统则只把进程的部分页面放
入内存,其它大部分页面在需要时再请求调入。因
此,进程大小不再受内存大小的限制。
• 系统将一个进程的虚拟空间分为不同的区,且每个
区对应有不同的页表。这些页表的虚拟地址都在系
统的核心区。
System
Ⅴ对核心区的地址变换及内
存分配都采用了与进程区不同的方法。这是因为核
心区的内容是常驻内存的,在执行中变化较少,并
被所有用户进程共享。