第四章UNIX的设备管理

上传人:re****.1 文档编号:567688881 上传时间:2024-07-22 格式:PPT 页数:79 大小:384.02KB
返回 下载 相关 举报
第四章UNIX的设备管理_第1页
第1页 / 共79页
第四章UNIX的设备管理_第2页
第2页 / 共79页
第四章UNIX的设备管理_第3页
第3页 / 共79页
第四章UNIX的设备管理_第4页
第4页 / 共79页
第四章UNIX的设备管理_第5页
第5页 / 共79页
点击查看更多>>
资源描述

《第四章UNIX的设备管理》由会员分享,可在线阅读,更多相关《第四章UNIX的设备管理(79页珍藏版)》请在金锄头文库上搜索。

1、第四章第四章 UNIXUNIX的设备管理的设备管理 设备管理的主要任务是管理系统中的所有外部设备。UNIX系统把设备分为两类: (1) 块设备。用于存储信息,其对信息的存取是以信息块为单位的,如通常的磁盘、磁带等; (2) 字符设备。用于输入/输出程序和数据,其对信息的存取是以字符为单位的,如通常的终端设备、打印机等。 4.1 4.1 设备缓冲管理设备缓冲管理 在现代操作系统中,无论是字符设备还是块设备,在进行I/O操作时,都须借助于缓冲,以缓和 CPU与 I/O设备速度不匹配的矛盾。在UNIX系统中也不例外,该系统分别为字符设备和块设备设置了缓冲池。 一一 块设备缓冲队列的结构块设备缓冲队列

2、的结构 UNlX系统在文件子系统和块设备驱动程序之间设置了大量的数据缓冲区,供磁盘和磁带机使用,以减少对磁盘的I/O操作次数。每个缓冲区的大小与盘块的大小相当,以便在一个缓冲区中存放一个或多个磁盘块内容。盘块的大小一般在5124096字节之间。由于盘块缓冲区的容量较大,使用上也较复杂,因此UNIX系统中的盘块缓冲区的组成方式不同于字符缓冲区。 1 数据缓冲区及其首部 每一个数据缓冲区均由两部分组成:一部分是用于存放数据本身的数据缓冲区,另一部分是缓冲控制块,也称缓冲首部,用于存放缓冲区的管理信息。两者一一对应,但缓冲首部与缓冲区在物理上并不相连,只是在缓冲首部中用一个指向对应缓冲区的指针,把两

3、者联系起来(如下图所示)。 设备号 快 号状 态 指向数据缓冲区指针指向散列队列上的前一个缓冲区的指针指向散列队列上的后一个缓冲区的指针指向空闲表上的前一个缓冲区的指针 指向空闲表上的后一个缓冲区的指针 1 数据缓冲区及其首部 每一个数据缓冲区均由两部分组成:一部分是用于存放数据本身的数据缓冲区,另一部分是缓冲控制块,也称缓冲首部,用于存放缓冲区的管理信息。两者一一对应,但缓冲首部与缓冲区在物理上并不相连,只是在缓冲首部中用一个指向对应缓冲区的指针,把两者联系起来(如下图所示)。 设备号 快 号状 态 指向数据缓冲区指针指向散列队列上的前一个缓冲区的指针指向散列队列上的后一个缓冲区的指针指向空

4、闲表上的前一个缓冲区的指针 指向空闲表上的后一个缓冲区的指针 缓冲区头部结构struct buf Int b_flags;/是个标志位,含状态信息,包括有B_READ,B_WRITE,等 struct buf *b_forw; /* 后面 */ struct buf *b_back; struct buf *av_forw; struct buf *av_back; int b_dev; /* 主设备号 */ int b_wcount; /* 传输数据 */ char *b_xmem; /* 核心地址高字节 */ char *b_blkno; /* 块号 */ char b_error; /*

5、 返回字符 */ char *b_resid; /* 错误后,没有被传输的字 */bufNBUF 缓冲首部还包括设备号和块号,以分别指出对应的文件系统和磁盘上的数据块号。必须说明,在UNIX System V中,设备号并非物理设备号,而是逻辑设备号,核心把每一个文件系统看作一个逻辑设备。缓冲首部中的状态字段用于指出对应缓冲区的当前状态,用于表示缓冲区是否空闲、缓冲区是否为延迟写、是否有进程正在等待该缓冲区变为空闲、核心是否正在读或写该缓冲区等。缓冲首部还包括两个空闲链表指针及两个散列队列指针。前者分别指向空闲链表中的上一个和下一个缓冲区首部;后者分别指向散列队列中的上一个和下一个缓冲区首部。s

6、truct devtab char d_active ; /*忙的标志设备状态信息 */ char d_errcnt; /* 错误返回的数目 */ struct buf *b_forw; /* 相应设备相关联的各缓存列表第一个缓冲区 */ struct buf *b_back; /* 相应设备相关联的各缓存列表最后一个缓冲区 */ struct buf *actf; /* 空闲链表的头指针 */ struct buf *actl; /* 空闲链表的尾指针 */ 2 2、缓冲池结构、缓冲池结构 (1) 空闲链表。为了对缓冲区进行管理,在核心中设置一个双向链接的空闲链表。系统初启时,将所有的、缓冲

7、首部都链入空闲链表中。当需要一空缓冲区时,从空闲链表的首部摘下一缓冲区;释放一缓冲区时,将它挂在空闲链的末尾。 空闲表头标缓冲区1缓冲区2缓冲区n空闲表头标缓冲区2缓冲区1向前指针向后指针 (2) 散列队列。为了加速对缓冲区的查找,系统把所有的缓冲区分设备地、按其块号所计算的散列值的不同,组织成多个散列队列,每个散列队列仍是一个双向链,其中缓冲区的数目不断地变化,各块号的散列值用散列函数计算。 由于每一缓冲区都在一个散列队列中,而空闲缓冲区又应链入空闲链中,因此一个空缓冲区可同时链入两个从列中,并使对一空缓冲区的查找可通过两种方法来进行:(1)若要求获得任一空缓冲区,从空闲链上去摘取第一个缓冲

8、区是最方便的,(2)若要求寻找一特定的空缓冲区,则搜素散列队列更方便。blmno 0 mod 4blmno 1 mod 4 blmno 2 mod 4 blmno 3 mod 4281798346459750109935 3 3 缓冲区的分配缓冲区的分配 核心调用getblk过程分配缓冲区。当要读磁盘数据时,核心首先检查要读入的盘块内容是否已在某个缓冲区中,若发现已在某个缓冲区中,便不必再从磁盘上读入。仅当数据未在任何缓冲区中时,核心才须从磁盘上将数据读入,这时才须为其分配一空闲缓冲区。类似地,当要把数据写入一特定盘块时,核心应先检查该块内容是否已在某缓冲区中,仅当该块内容尚不在缓冲区中时,才

9、须调用getblk过程,分配一空缓冲区。获取空闲缓冲区时应提供的输入参数是文件系统号和磁盘块号。 getblk过程描述如下: getblk过程分配缓冲区时,可分为五种情况: (1) 缓冲块在散列队列上,并且它的缓冲区是空闲的。 (2) 缓冲块在散列队列上,并且它的缓冲区当前为忙。 (3) 缓冲块不在散列队列上,从空闲表中分配一缓冲区。 (4) 缓冲块不在散列队列上,且空闲缓冲区表为空。 (5) 缓冲块不在散列队列上,且试图从空闲表中分配一缓冲区时,在空闲表中找到一个标为“延迟写”标记的缓冲区。 getblk过程描述如下: getblk(文件系统号,块号) while(没找到缓冲区) if(块在

10、散列队列中) if(块忙) /* 第五种情况第五种情况 */ sleep(等候“缓冲区变为空闲”事件); continue; /*回到while循环 */ 为缓冲区标记上“忙”; /* 第一种情况第一种情况 */ 从空闲表中摘下缓冲区; return(缓冲区); else if(空闲表上无缓冲区)(空闲表上无缓冲区) /* 第四种情况第四种情况 */ sleep(等候“任何缓冲区变为空闲”事件); continue; /*回到while循环 */ 从空闲表上摘下缓冲区; if(缓冲区被标记为“延迟写”) /* 第三种情况第三种情况 */ 把缓冲区异步写到磁盘上;把缓冲区异步写到磁盘上; con

11、tinue; /*回到while循环 从旧散列队列中摘下缓冲区; 把缓冲区投入新散列队列; return(缓冲区); blmno 0 mod 4blmno 1 mod 4 blmno 2 mod 4 blmno 3 mod 4281798346459750109935blmno 0 mod 4blmno 1 mod 4 blmno 2 mod 4 blmno 3 mod 4284649850109935317597空闲表头标空闲表头标a) 在第一散列队列上搜索第4块b) 在空闲表上摘下第4块缓冲区分配的第一种情况 blmno 0 mod 4blmno 1 mod 4 blmno 2 mod 4

12、 blmno 3 mod 428179846459750109935blmno 0 mod 4blmno 1 mod 4 blmno 2 mod 4 blmno 3 mod 4284649850109935317597空闲表头标空闲表头标a) 搜索第18块,不在高速缓冲中b) 在空闲表上摘下第1个缓冲区,分配给第18块缓冲区分配的第二种情况18 blmno 0 mod 4blmno 1 mod 4 blmno 2 mod 4 blmno 3 mod 42817983186459750109935blmno 0 mod 4blmno 1 mod 4 blmno 2 mod 4 blmno 3 m

13、od 4284649850109935317597空闲表头标空闲表头标a) 搜索第18块,空闲表上头两个缓冲区标记为延迟写b) 写第3、5块,把原分配给的第4块的缓冲区改为分配给第18块缓冲区分配的第三种情况延迟延迟写写 blmno 0 mod 4blmno 1 mod 4 blmno 2 mod 4 blmno 3 mod 4281798346459750109935blmno 0 mod 4blmno 1 mod 4 blmno 2 mod 4 blmno 3 mod 4284649850109935317597空闲表头标空闲表头标搜索第18块,空闲表为空搜索第99块,该块忙缓冲区分配的第

14、四种情况忙缓冲区分配的第五种情况 4 4、缓冲区的释放、缓冲区的释放 当核心用完某缓冲区时,可调用brelse过程将它释放,此前可能有些进程因等待使用该缓冲区而睡眠,此时释放者进程应将它们唤醒。此外,还可能有进程因空闲链表空而处于等待状态,同样也应将它门唤醒。如果所释放的缓冲区中的数据是有效的,为使以后在某进程需要它时,能直接从缓冲区中读出而不必启动磁盘的I/O操作,可将该缓冲区链入空闲链表的尾部;否则(缓冲区中数据无效)应将它填入空闲队列的头部。空闲链表属于临界资源,为了保证其操作的互斥性,UNIX系统是通过提高处理机执行时的运行级,将中断封锁来实现的。brelse过程的描述如图5所示。 b

15、relse 唤醒等待“无论哪个缓冲区变为空闲”这一事件的所有进程 唤醒等待“这个缓冲区变为空闲”这一事件发生的所有进程 提高处理机的运行级以封锁中断 缓冲区内容是否有效? 将缓冲区链入空闲表首部 将缓冲区链入空闲表尾部 降低处理机优先级 给缓冲区解锁 返 回 图5 brelse过程的描述高速缓冲的优缺点: (1) 缓冲区的使用提供了统一的磁盘存取方法,因为内核不凶大勺I/O的原因。 (2) 系统对进行I/O的用户进程没有做对齐数据限制。 (3) 高速缓冲的使用可减少访盘次数,从而提高整个系统的吞吐量,减少响应时间。 (4) 缓冲区算法有助于确保文件系统的完整性,因为它们维护的一个公共的、包含在

16、高速缓冲中的磁盘块的单一映像。 (5) 高速缓冲的使用,使得当往用户进程中读或从用户进程中写时需要一次额外的数据拷贝过程。 4.2 核心与驱动程序的接口设备开关表 在UNIX系统中,每类设备都有一个驱动程序,用它来控制该类设备。任何一个驱动程序通常都包含了用于执行不同操作的多个函数,如打开、关闭、启动设备、读和写等函数。为使核心能方便地转向各函数,系统为每类设备提供了一个设备开关表,其中含有该类设备的各函数的入口地址。 通常,字符设备和块设备的驱动程序有所不同,相应地,它们所包含的函数也不完全相同。由系统中所有字符设备的设备开关组成一张字符设备开关表,由系统中所有块设备的设备开关组成一张块设备

17、开关表。不论是哪种设备开关表,表中的每一行都是一类设备驱动程序的各函数的人口地址;表的每一列是执行相同操作的不同(设备类型)函数。下图给出了设备开关表与系统调用和驱动程序间的关系。从图中可以看出,设备开关表是核心与驱动程序间的接口,系统调用通过设备开关表转向相应驱动程序的函数。 文件子系统 open close read write ioctl open close mount unmount read write高速缓存块 设 备 开 关 表 字 符 设 备 开 关 表 Open close read write ioctl驱 动 程 序设 备 中 断 处 理 程 序Open close s

18、trategy 驱 动 程 序设 备 中 断 处 理 程 序中断向量中断向量 设备中断 1 块设备开关表 struct bdevsw int (*d_open)();/open函数的入口函数 int (*d_close)(), int (*d_stragegy)(); int d_tab;bdevsw; 这些都是函数指针,bedvsw中每一项都代表一个设备类型。这个结构前三个字段是函数指针。这样的结构设计巧妙,知道了这些指针的话,就可以让系统调用不同设备驱动程序的open,close,及策略过程。如果,要增加一个不同的块设备,只需bdevsw数组增加一个bedvswde的结构,就可以了。最后一

19、个应该是一个指向后面将要提到的devtab结构。 系统为每一类块设备设置一个设备开关,如下图所示。其中,第一行为0号块设备的开 表 项关,它包括三个:(1) gdopen:是0号设备专用的打开函数的入口地址,该函数用于在调用进程与被打开设备间,建立起一个连接,并初始化该设备驱动动程序的数据结构;(2)gdclose:是0号设备专用的关闭函数的入口地址,该函数用于终止调用进程与设备之间的连接;(3) gdstrategy :是策略函数的入口地址,该函数用于在数据缓冲区与块设备之间传输数据。块设备开关表的第二行是1号块设备的开关。 块 设 备 开 关 表 表项 open close strateg

20、y 0 gdopen gdclose gdstrategy 1 Gtopen gtclose gtstrategy 2 字符设备开关表 下图给出了字符设备开关表。表中共有六行,表明有六类字符设备驱动程序。整个驱动程序含有下述五个函数的入口地址:(1)用于打开特定字符设备的函数,不同字符设备的打开函数不同,(2)关闭特定字符设备的函数,(3)读特定字符设备函数,(4)写特定字符设备函数,(5)用于预置该设备参数的函数及读取该设备预置参数的函数等的入口地址。 块 设 备 开 关 表 表项 open close read write ioctl 0 conopen conclose conread

21、conwrite conioctl 1 dzbopen dzbclose dzbread dzbwrite dzbioctl 2 sysyopen sysclose sysread syswrite sysioctl 3 nulldev nulldev nulldev nulldev nulldev 4 gdopen gdclose gdread gdwrite gdioctl 5 gtopen gtclose gtread gtwrite gtioctl 4.3 4.3 系统调用与驱动程序接口系统调用与驱动程序接口 对对于那些使用文件描述符的系统调用,内核从用户文件描述符的指针找到内核文件表

22、以及索引节点,并检查文件类型,根据需要存取块设备或宇符设备开关表。它从索引节点中抽取主设备号和次设备号,使用主设备号作为索引值进人适当的开关表,根据用户所发的系统调用来调用驱动程序中的函数。设备文件与正规文件的系统调用间的一个重要区别是:当内核执行驱动程序时,特殊文件的索引节点是不上锁的。这是因为驱动程序频繁地睡眠,等待着硬连接或数据的到来,因此内核不能确定一个进程要睡眠多长时间。如果对索引节点上锁,则其他存取此索引节点的进程(如通过系统调用stat)会无限期地睡眠下去,因为另一进程正在驱动程序中睡眠。 设备驱动程序把系统调用的参数解释为对该设备的适当的参数。一个驱动程序维护着描述它所控制的每

23、一设备单元状态的数据结构,根据该状态以及要做的动作(如输人或输出数据)执行驱动程序中的子程序和中断处理程序。下面,我们将详细的叙述每一个接口。 1系统调用系统调用open 为了以系统调用open打开一个设备,内核使用与它打开正规文件同样的过程,即:分配一个内存索引节点,增加其引用数,赋予一个文件表表项和用户文件描述符,内核最后将用户文件描述符返回给调用的进程。所以打开一个设备看上去就像打开一个正规文件。然而,它在返回到用户态以前,调用设备专用的打开过程(下图):对块设备,它调用块设算法备开关表中的打开过程;对字符设备,它调用字符设备开关表中的打开过程。如果一个设备既是一个块设备又是一个字符设备

24、,内核将根据用户所打开的特定的设备文件,调用适当的打开过程。依赖于所用的驱动程序,这两个打开过程甚至可以是相同的。 设备专用的打开过程在调用的进程与被打开的设备之间建立起一个连接,并初始化私有的驱动程序数据结构。举例来说,对一个终端,打开过程可以让进程进人睡眠,直到机器检测到一个(硬件)载波信号,该信号指示有个用户正试图注册到机器。然后它根据适当的终端的预置参数(如终端波特率)来初始化驱动程序数据结构。对于软设备如系统存储器,打开过程可能不需要做初始化工作。 算法 open * 专为设备驱动程序专为设备驱动程序 */ 输人:路径名,输人:路径名, 打开方式打开方式 输出:文件描述符输出:文件描

25、述符 将路径名交换成索引结点,增加索引结点引用数,将路径名交换成索引结点,增加索引结点引用数, 与正规文件打开一样,分配文件表中表项、用户文件描述符;与正规文件打开一样,分配文件表中表项、用户文件描述符; 从索引结点取主、次设备序号;从索引结点取主、次设备序号; 保存上下文(算法保存上下文(算法 setjmp)以防驱动程序需要执行)以防驱动程序需要执行 Iongjmp; if(块设备)(块设备) 使用主设备号作为块设备开关表的索引;使用主设备号作为块设备开关表的索引; 调用相应该索引的驱动程序打开过程:调用相应该索引的驱动程序打开过程: 传递参数为次设备号、打开方式;传递参数为次设备号、打开方

26、式; else 使用主设备号作为字符设备开关表索引;使用主设备号作为字符设备开关表索引; 调用相应该索引的驱动程序打开过程:调用相应该索引的驱动程序打开过程: 传递参数为次设备号、打开方式;传递参数为次设备号、打开方式; if(open在驱动程序中失败)在驱动程序中失败) 减少文件表、索引结点引用数;减少文件表、索引结点引用数; 当打开一个设备时,如果由于某种外部的原因进程必须睡眠,可能会发生这样的情况:从睡眠中唤醒该进程的事件可能永远不出现。例如,如果老也没有用户注册到某特定的终端时,打开终端的getty进程会睡眠很长时间,直到一个用户试图注册。内核必须能够从睡眠中唤醒该进程,并在收到一个软

27、中断信号时取消open调用,即:由于未能打开设备,它必须重置索引节点、文件表表项、用户文件描述符这些它在进人驱动程序以前已分配的资源。因此,内核在进人设备专用的 open子程序以前,应使用算法 setjmp保存进程上下文,如果进程由于软中断信号被从睡眠中唤醒,那么内核使用算法longimp将进程上下文恢复到它进人驱动程序之前的状态,并且释放它为了打开设备所分配的全部数据结构。类似地,驱动程序能捕俘这一软中断信号,并当需要时将私用的数据结构清除掉。当驱动程序遇到错误情况时,比如当一用户试图存取一个未被配置的设备时,内核也要再调整文件系统的数据结构。在这些情况下,系统调用open失败。 进程可以规

28、定各种各样的选择项以限定对设备的打开。最普通的选择项是“不延迟”,它的意义是:在打开过程中如果设备没有准备好,进程将不进人睡眠,系统调用立即返回,而用户进程不知道是否建立了硬连接。下面我们将看到,以“不延迟”打开一个设备也会影响系统调用read的语义。 如果一个设备被打开多次,如第5章所述,则内核巧妙地处理用户文件描述符、索引节点以及文件表表项,为每一个系统调用open请求设备专用的打开过程。这样,设备驱动程序能对一个设备被打开了多少次进行计数,并且当此计数值不恰当时,让open调用失败。举例来说,允许多个进程打开一个终端进行写操作以便用户间能交换消息是有意义的。但是,允许多个进程同时打开一个

29、打印机进行写操作就讲不通了,因为这会造成它们彼此的数据被改写。上述区别与其说是实际的区别倒不如说是实现上的区别:允许同时对终端写促进了用户间的通信;阻止同时对打印机写增加获得可读的打印输出的机会。 2系统调用close 一个进程通过系统调用close断开它与一打开设备的连接。然而,仅当该设备的最后一个关闭操作到来时,也就是说,仅当没有其他进程仍然打开着该设备时,内核才调用那个设备专用的关闭过程。这是因为关闭过程要终止与硬件的连接,很明显,这必须等到没有进程再要存取该设备的时候。由于在每一次系统调用open时内核调用设备的打开过程,而仅调用设备的关闭过程一次,因此该设备驱动程序永远不能确切地知道

30、有多少进程仍在使用那个设备。如果不仔细地进行编程,驱动程序会很容易使它们自己陷入混乱状态。例如如果它们在关闭过程中睡眠,而在系统调用。close完成前另一个进程打开这个设备,如果打开和关闭的组合导致一个无法辨认的状态,则这个设备会变成无用的设备。 关闭一个设备蹬算法类似于关闭一个正规文件的算法(如下图),然而,在内核释放索引结点以前,它进行设备文件专用的操作: (1)它搜索文件表以确定没有其他的进程仍然打开着该设备。根据文件表中的引用数来指示这是一个设备的最后一次关闭操作是不够的,因为几个进程可以通过不同的文件表表项存取该设备;同样,依靠索引节点中引用数也是不够的,因为几个设备文件可以表示同一

31、设备。 (2)对于一个字符设备,内核调用设备的。close过程并返回用户态。对于一个块设备,内核搜索安装表以确认该设备不包含一个已安装的文件系统。如果该块设备上含有一个已安装的文件系统,内核不能调用设备的关闭过程,因为这不是该设备的最后一次关闭操作。甚至如果该设备虽已不包含一个已安装的文件系统,但高速缓冲中仍然可能包含有先前安装的文件系统遗留下来的数据块,而且因为它们是以“延迟写”标记的,还从未写回设备。因此,内核在调用设备关闭过程以前,先要搜索高速缓冲中这样的数据块,把它们写回该设备。在关闭设备之后,内核再一次扫描高速缓冲,使所有装有现在已关闭的设备数据块的缓冲无效,因而允许含有有用数据的缓

32、冲在高速缓冲中停留更长些。 (3)内核释放设备文件的索引节点。算法 close * 设备专用 *输人:文件描述符输出:无 执行正规的算法close; if(文件表引用数非0) goto finish; if(存在另一个打开文件其主、次设备号与欲关闭文件的相同) gotofinish;* 毕竟不是最后的关闭 * if(字符设备) 以主设备序号作为字符设备开关表的索引; 调用驱动程序关闭子程序:参数为次设备号; if(块设备) if(设备已安装) goto finish; 将高速缓冲中该设备的数据块写回设备; 用主设备号作为块设备开关表的索引; 调用驱动程序关闭子程序:参数为次设备号; 使高速缓冲

33、中该设备的数据块无效; finish:释放索引节点; 2策略接口:strategy () 内核使用策略接口(strategy interface)在高速缓冲和设备之间传送数据。字符设备的读和写过程有时使用它们的(对应的块设备的)策略过程来在设备与用户地址空间之间直接传送数据。策略过程可以把对一个设备的IO作业送人一个工作表队列,或者做更复杂的调度IO作业的处理工作。驱动程序可以建立与一个物理地址之间的数据传送,或者如果需要的话,建立与很多物理地址的数据传送。内核把一个缓冲头部地址传递给驱动程序策略过程,该头部包含一个为从设备传送数据或传送数据到设备的(页面)地址及大小的表,这也是第9章中讨论的

34、对换操作的工作原理。就高速缓冲而言,内核从一个数据地址传送数据,而当对换操作时,内核从许多数据地址(页面)传送数据。如果数据是从用户地址空间拷贝或拷贝到用户地址空间去的,则驱动程序必须将进程(或者至少有关的页面)锁在存储器中,直到IO传送完成。 举例来说,在安装一个文件系统以后,内核用设备号和索引节点号识别该文件系统中每一个文件,设备号是由主设备号和次设备号编码得到的。当内核从一个文件存取一块时,它把设备号和块号拷贝到缓冲头部中去。当高速缓冲算法(如 bread或bwrite)存取该磁盘时,它们调用由主设备号所指定的策略过程,策略过程则使用在缓冲头部的次设备号和块号来确定到设备上的什么地方去寻

35、找数据,并用缓冲地址来确定数据应当传送到什么地方去。类似地,如果一个进程直接地存取一个块设备(即该进程打开那个块设备并读或写它),它使用高速缓冲算法,而接口按照刚刚描述的方法工作。 4系统调用ioctl() 系统调用ioctl是对UNIX系统较早的版本中提供的专门用于终端的系统调用: stty(预置终端参数)和gtty(取终端预置参数)的一种普遍化,它为所有的设备专用命令提供一个一般的、万能的人口点。它允许一个进程去预置与一个设备相联系的硬件选择项和与一个驱动程序相联系的软件选择项。由系统调用i。ti规定的专门的动作对每个设备是不同的,并由设备驱动程序定义。使用系统调用ic。ti的程序必须知道

36、它们正在与什么类型的文件打交道,因为这些都是设备专用的。这对于系统不应在不同文件类型间加以区别的一般规则是一个例外。系统调用ioctl()的语法是: iocttl(fd,command, arg); 其中fd是先前的一个系统调用返回的文件描述符; command是使驱动程序完成一个特定动作的请求命令,而arg是对该命令的一个参数(可能是指向一个结构的指针)。命令是驱动程序专用的,因此,每个驱动程序根据其内部的说明解释命令,而数据结构arg的形式依赖于该命令。驱动程序可以根据预先定义的形式从用户空间读人数据结构arg,或者它们可以用arg将设备的预置参数写回到用户空间去。例如,ioctl接口允许

37、用户置终端波特率;允许用户在磁带驱动器上反绕磁带;最后它允许一些网络操作如规定虚电路数目和网络地址。 3 3 中断处理程序中断处理程序 一个中断的出现将引起内核执行一个中断处理程序,而执行哪一个中断处理程序是根据发出中断的设备和中断向量表中的偏移量的相互关系决定的。内核调用该设备专用的中断处理程序,将设备号或其他参数传递给它,以便识别引起中断的特定的设备单元。下图给出了设备中断示意图。ttyintr0ttyintr1consintrprintintrtty00tty01.tty07tty08tty15consolepriinter00.printer03 中断向量硬件底板外部设备 4.5 4.

38、5 磁盘设备驱动程序磁盘设备驱动程序 磁盘驱动程序的主要功能是: (1)把由逻辑设备号和盘块号组成的文件子系统地址,转换为磁盘上特定的扇区号; (2)装配磁盘控制器的各个寄存器,如磁盘地址寄存嚣、内存总线地址寄存器、字计数器以及控制状态寄存器等; (3)对磁盘块进行读、写。前两个功能与具体的磁盘有关,相对也较简单;而第三个功能则是驱动捏序的最主要功能。 磁盘驱动程序把由一个逻辑设备号和块号组成的文件系统地址翻译成磁盘上特定的扇区号。驱动程序使用以下两种方法之一来得到该地址:或者策略程序使用缓冲池中的一个缓冲,而该缓冲头部含有设备号和块号;或者将逻辑设备号(次设备号)作为一个参数传递给读过程或写

39、过程,它们再把保留在11区的字节偏移量变换为适当的块地址。磁盘驱动程序用设备号来识别物理盘以及所使用的特定的磁盘段,维护内部表格以便找到一个磁盘段开始的扇区。最后,它把文件系统的块号加到起始扇区号上去,以便识别IO传送所用的扇区号。 一、磁盘的读写方式 1. 读方式。在UNIX系统中有两种读方式: (1)一般读方式。把盘块中的信息读入缓冲区,由bread过程完成; (2)提前读方式,在一个进程程序顺序地读一个文件的各个盘块时,会预见到所要读的下一个盘块,因而在请读读出指定盘块(作为当前诀)的同时,可要求提前将下一个盘块(提前块)中的信息读入缓冲区。这样,当以后需要该盘块的数据时,因它已在内存中

40、,这就缩短了读数据时间,从而改善了系统性能。提前读功能由breada过程完成。 2. 写方式。UNIX系统有三种写方式: (1)一般写方式。真正把缓冲区中的数据写入磁盘上,且进程须等待写操作完成,由进程bwrite完成; (2)异步写方式。进程无须等待写操作完成便可返回,异步写过程为bawrite; (3)延迟写方式。该方式并不真正启动磁盘,而只是在缓冲首部设置延迟写标识,然后便释放该缓冲区,并将该缓冲区链入空闲链表的末尾。以后,当有过程申请到该缓冲区时,才将它写入磁盘。引入延迟写的目的是为了减少不必要的磁盘I/O,因为只要没有进程申请到此缓冲区,其中的数据便不会写入磁盘,倘若再有进程需要访问

41、其中的数据时,便可直接从空闲链表中摘下该缓冲区,而不必从磁盘读入。 二、读过程bread和breada 1. 一般读过程(bread)。该过程的输入参数是文件系统号(即逻辑设备号)及块号。进入该过程后,先调用getdlk过程申请一缓冲区,若缓冲区首部标明该缓冲区中数据是有效的,便无须再从磁盘读入,直接返回;若所需数据尚未读入,应先填写缓冲区首部,如设置读标志,以表明本次是读操作,再设置块的初始字符计数值(如1024),再通过块设备开关表转入相应的策略过握,启动磁盘传送。由于一般读方式进程要等待读操作完成,故须调用sleep过程使自己睡眠,直至读操作完成时,由中断处理程序将它唤醒,才最后地将缓冲

42、区首部的指针bp作为输出参数返回给调用进程。bread过程的流程见图9。 bread调用getdlk过程申请一缓冲区 缓冲区中数据是否有效 填写缓冲控制块,设置读标志,计数值 通过块设备开关表转入设备启动程序 设备启动程序 调用sleep使自己睡眠 返 回图9 bread过程的流程 算法bread /* 读块 */输入:文件系统块号;输出:含有数据的缓冲区; 调用getblk,得到该块的缓冲区; if(缓冲区数据有效) return(缓冲区); 启动磁盘读; sleep(等待”读盘完成”事件); return(缓冲区); 在文件系统的介绍中,我们会看到,当一个进程顺序读一个文件时,较高层次的内

43、核模块可以会预先把下一磁盘块也读进来。 2.提前读过程breada。该进程的输入参数是当前读的文件系统号(设备号)、盘块号,以及提前读的文件系统号、盘块号。进入该过锃后,先判别当前块是否在缓冲池中,若不在,须调用getblk为其分配缓冲区;若缓冲区中的数据无效,则应填写缓冲区首部,通过设备开关表转入策略过锃,启动磁盘进行读入;若当前块已在缓冲池中,或所分配的缓冲区中数据有效,都将转去读提前块。 若提前块的数据缓冲区不在缓冲池中,同样要调用getblk过程为读提前块分配一缓冲区。若所得缓冲区中的数据有效,则调用brelse过程将该缓冲区释放,以便其它进程可对它进行访问,否则,填写缓冲区首部后启动

44、磁盘。最后,若当前块缓冲区在缓冲池中,则调bread过程去读当前块;否则,调sleep使自己睡眠,以等待读操作完成。在读操作完成而被唤醒后,返回该缓冲区首部的指针。算法breada /* 读块与提前读 */输入:(1)立即读的文件系统块号; (2)异步读的文件系统块号; 输出:含有立即读的数据的缓冲区; if(第一块不在高速缓冲中) 调用getblk,为第一块获得缓冲区; if(缓冲区数据无效) 启动磁盘读; if(第二块不在高速缓冲中) 调用getblk,为第二块获得缓冲区; if(缓冲区数据有效) 释放缓冲区; else 启动磁盘读; if(第一块本来就在高速缓冲中) 读第一块(调用bre

45、ad); return(缓冲区); sleep(等待第一个缓冲区包含有效数据的事件); return(缓冲区); 直接地读和写磁盘的程序是危险的,因为它们可能读或写敏感的数据,危害系统的安全性。因此系统管理员必须通过对磁盘文件设置适当的许可权来保护块和原始的接口。例如,磁盘文件“devdskls”和“devrdsk15”的所有者应当是“根”,而它们的许可权应是只允许“根”去读该文件,不允许任何其他的用户读或写。 直接地读和写磁盘的程序也会破坏文件系统数据的一致性。文件系统的算法与磁盘的IO操作是紧密配合的,为的是保持对磁盘数据结构有一致的看法,包括磁盘块自由链表和从索引节点到直接和间接的数据块

46、的指针。直接存取磁盘的进程绕过这些算法,即使它们是经过仔细地编程的,当其他文件系统的活动正在进行时,如果它们运行,也仍然存在着一致性问题。 直接地读和写磁盘可能导致数据读取错误。例如,如果一个进程向一个块设备写,另一个进程在同一地址从一个原始设备读,第二个进程读的数据可能不是第一个进程写人的数据,因为第一个进程写人的数据可能仍在高速缓冲中,而不在磁盘上。然而,如果第二个进程也是从块设备读,只要新数据在高速缓冲中存在,它就会自动地拿到该数据。 三、写过称bwrite、bawrite和bdwrite 1. 一般写过程bwrite。该过程的输入参数是缓冲区指针bp。进入该过程后,根据bp指针找到缓冲

47、区首部,设置缓冲区首部的初值,通过设备开关表转入策略过程,启动磁盘。如是一般写,应等侍I/O完成,为此须调sleep使自己睡眠,I/0完成再被唤醒后,调brelse释放该缓冲区。如是异步写且有延迟过程,启动磁盘写标志,则给缓冲区打上旧标志后放入空闲链表的首部。bwrite过程见图11所示。 2.异步写过程bawrite。它与一般写过程很相似,但不须等待I/O完成即可返回。进入bawrite后,设置异步写标志,便调用bwrite过程实现之。 3.延迟写过程bdwrite。延迟写过程也很简单。这里只须设置延迟写标志及数据有效标志,再调用brelse过程将该缓冲区释放并链入空闲链表的尾部。以后,当某

48、进程调用getblk获得该缓冲区时,再用异步写方式将缓冲区的内容写入磁盘。 bwrite 用bp找到缓冲首部填写缓冲首部 通过开关表进入gdstrategy过程,启动磁盘 是异步写?调sleep使自己睡眠 延迟写? 调brelse释放该缓冲 将缓冲放在空闲链 NYY返回 图11 bwrite过程的流程bwrite(struct buf *bp) register struct buf *rbp; register flag; rbp=bp; flag=rbp-flags; rbp-flags=&”(B_READ|B_DONE|B_ERROR|B_DELWRI); rbp-b_wcount=-2

49、56; (*bdevswrbp-b_dev.d_major.d_strategy)(rbp); /*启动磁盘写; */ if (flags&B_ASYNC)=0) /* I/O同步 */ iowait(rbp); /*等待”I/O完成”事件 */ brelse(rbp); /*释放缓冲区 */ else if(flag&BDELWRI)=0) /* 缓冲区是否标记着延迟写 */ geterror(rbp); /*为缓冲区做标记以放到空闲表头部 */bdwrite(bp)struct buf *bp;register struct buf *rbp; rbp=bp; dp=bdeswrbp-b_

50、dev.d_major.d_tab; if(dp=&tmtab|dp=&httab) bawrite(rbp); else rbp-b_flags=|B_DELWRI|B_DONE; brelse(rbp); 4.6 字符设备驱动程序 字符驱动程序具有与其他驱动程序相同的功能,即控制从字符设备来和到字符设备去的数据。然而,由于字符设备是用户与系统的接口,所以字符设备又是特殊的。为使用户交互式的使用UNIX系统,字符设备驱动程序包含一个与行规则(line discipline)模块的内部的接口,行规则程序的作用是对输人和输出的数据进行解释。在标准方式(canonical)下,行规则程序把在键盘上

51、敲人的原始数据序列变换成一种标准的形式(即用户真正的意思是什么),然后再把数据送给一个接收进程;同样地,行规则程序把一个进程输出的原始输出数据变换成用户所期望的形式。在原始方式(raw)下,行规则程序仅在进程和终端之间传送数据,不做上述变换。 一 字符表clist 字符表,或称为Clist,是字符缓冲cblock的变长度的链表,并携带有表中的字符计数。一个cblock含有一个指向该链表中下一个cblock的指针,一个用来存放数据的小的字符数组,一组用来指示cblock中有效数据位置的偏移量(下图)。起始偏移量指示数组中第一个有效数据的位置,终止偏移量指示第一个无效数据的位置。 7 14 g a

52、 r b a g e | e q n | 下个Cblock 指针起始位移量终止位移量 字符数据 1 2 3 4 5 6 7 8 9 10 内核维护一个空闲cblock的链表,并规定在Clist和cblock上有六种操作: (1) 它有一个从空闲表中分配一个cblock给驱动程序的操作。 (2) 它有一个把一个cblock归还给空闲表的操作。 (3) 内核可以从一个Clist中提取一个字符:它从Clist表中第一个cblock中移出一个字符,并调整Clist的字符计数和到该cblock的索引值,使以后的操作不再提取同一字符。如果提取操作移出的是某。block中最后一个字符,则内核把腾空的cblo

53、ck放回空闲表,并调整clist的指针。如果提取操作完成后一个Clist中已不包含字符,则内核返回空白字符。 (4) 内核能把一个字符放入clist表的末尾,它找到该Clist表的最后一个cblock,将该字符放进去,并调整偏移量。如果该cblock已满,则内核分配一个新的 cblock,将之链入该Clist的末尾,并把字符放人新Cblock中去。 (5) 内核可以从一个Clist表的开头移去一组字符,每次一个Cblock。这个操作等价于每一次移去一个Cblock的所有字符。 (6)内核可以把一个cblock的字符放到一个Clist表的末尾。 clist cblocks27 字符 0 8p I

54、 c f i I e 0 8 0 8 0 3 * I t b I l t r o f f l m m 26 字符 1 8 0 8 0 8 0 3 2 8 0 8 0 8 0 3 0 8 0 8 0 3 I c f i I e c f i I e25 字符 19 字符 * I t b I * I t b I * I t b I l t r o f f l t r o f f l t r o f f l m m l m m l m m clist cblocks22 字符 0 8p i c f i I e 0 8 0 6* I t b I l t r o f 23 字符 0 8 0 8 0 7 0

55、 8 0 8 0 8 0 8 0 8 0 8 0 1p i c f i I e p i c f i I e 24 字符 25 字符 * I t b I * I t b I * I t b I l t r o f f al t r o f f l t r o f f p i c f i l e c 二 标准方式下的字符设备驱动程序 1 写数据到字符设备的算法算法 terminal write while(尚有数据待从用户空间拷贝) if(tty结构填满待输出数据) 启动硬件写操作以便送出输出clist中数据; sleep(tty能接受更多数据的事件); continue; * 回到while循环

56、开始 * 从用户空间拷贝 cblbok大小的数据到输出 clist; 行规则程序变换制表符等; 启动硬件写操作以便送出输出clist中的数据; 2 2 读取字符设备上的数据读取字符设备上的数据算法 terminal read if(标准cIist中无数据) while(原始clist中无数据) if(tty是以“不延迟”选择打开的) return; if(tty是基于定时的原始方式且定时器未激活) 设置定时器唤醒(callout表); sleep(事件:数据从终端到来); * 原始clist上有数据 * if(tty是原始方式) 将全部数据从原始clist拷贝到标准clist; else *

57、tty是标准方式 * while(原始clist中有字符) 每次从原始。list拷贝一个字符到标准clist: 进行擦除、抹行处理; if(字符是回车待或文件尾) break;* 退出循环 * while(标准clist中有字符且欲读字节数未满足) 从标准clist的cblock拷贝到用户地址空间;4.7 UNIX4.7 UNIX的中断处理的中断处理 UNIX也系统状态分为:核心态和用户态。通常,也系统状态分为:核心态和用户态。通常,用户程序运行于用户态,核心程序和设备驱动程序用户程序运行于用户态,核心程序和设备驱动程序运行于核心态。核心态在最高级执行,在这一级任运行于核心态。核心态在最高级执

58、行,在这一级任何操作都可以执行;而应用程序则执行在用户态,何操作都可以执行;而应用程序则执行在用户态,在这一级处理器禁止对硬件的直接访问和对内存的在这一级处理器禁止对硬件的直接访问和对内存的未授权访问。在未授权访问。在UNIX系统中,有三种事件会导致系系统中,有三种事件会导致系统进入内核态统进入内核态设备中断、异常、自陷或软中断。设备中断、异常、自陷或软中断。中断作为其中之一的情况,当内核接收到控制权,中断作为其中之一的情况,当内核接收到控制权,它依赖于中断向量表控制转移方向,而其中包括处它依赖于中断向量表控制转移方向,而其中包括处理中断的底层程序的地址。理中断的底层程序的地址。 UNIX的中

59、断分为三种:的中断分为三种: 1硬件中断(如来自时钟和外设);硬件中断(如来自时钟和外设); 2软件中断(软件中断(software interrupt););内核处理中断的操作顺序是:内核处理中断的操作顺序是: (1)对正在执行的进程,保存其当前寄存器上下)对正在执行的进程,保存其当前寄存器上下文并创建一个新的上下文层。文并创建一个新的上下文层。 (2)确定中断源,识别中断类型。若可以的话,)确定中断源,识别中断类型。若可以的话,还识别中断的单元号。另外,系统依据接受中断时还识别中断的单元号。另外,系统依据接受中断时从机器中得到的数查询中断向量表,从而得到中断从机器中得到的数查询中断向量表,

60、从而得到中断处理程序的地址。处理程序的地址。 (3)内核调用中断处理程序。一般来说,系统是)内核调用中断处理程序。一般来说,系统是在新的上下文层中作中断的处理工作,将正在运行在新的上下文层中作中断的处理工作,将正在运行的进程的核心栈或者全局中断栈来存放中断处理程的进程的核心栈或者全局中断栈来存放中断处理程序的栈结构。序的栈结构。 (4)中断处理程序工作完毕前返回。内核执行一)中断处理程序工作完毕前返回。内核执行一系列特殊机器指令,恢复前一上下文层的寄存器上系列特殊机器指令,恢复前一上下文层的寄存器上下文和核心栈,让它们和中断发生时的情况一样,下文和核心栈,让它们和中断发生时的情况一样,并恢复该

61、上下文层的运行,使得进程就像从来没有并恢复该上下文层的运行,使得进程就像从来没有发生过中断一样继续运行。发生过中断一样继续运行。4.7.1 4.7.1 硬件中断处理硬件中断处理 硬件中断主要是来自硬件中断主要是来自I/O设备的中断,如设备请求、设备的中断,如设备请求、打印中断、掉电中断等等。硬件中断的作用是使打印中断、掉电中断等等。硬件中断的作用是使CPU从当前所执行的指令序列转移到另一道程序。从当前所执行的指令序列转移到另一道程序。硬件中断的过程如下:硬件中断的过程如下: (1)中断源的识别:)中断源的识别: UNIX每个外部中断源专用一条中断请求线,在将每个外部中断源专用一条中断请求线,在

62、将多个设备的中断信号送往多个设备的中断信号送往C P U的中断插脚之前,系的中断插脚之前,系统经常使用中断控制器来综合多个设备的中断。这统经常使用中断控制器来综合多个设备的中断。这样即可以节约样即可以节约C P U的中断插脚,也可以提高系统设的中断插脚,也可以提高系统设计的灵活性。中断控制器用来控制系统的中断,它计的灵活性。中断控制器用来控制系统的中断,它包括屏蔽和状态寄存器。设置屏蔽寄存器的各个位包括屏蔽和状态寄存器。设置屏蔽寄存器的各个位可以允许或屏蔽某一个中断,状态寄存器则用来返可以允许或屏蔽某一个中断,状态寄存器则用来返回系统中正在使用的中断。回系统中正在使用的中断。矢量单元矢量单元陷

63、入类型陷入类型优先级优先级 044总线超时 7010非法指令7014bpt_跟踪 7020ito7024电源故障7030仿真陷入指令 7034Trap指令7114I/O奇偶错7240程序中断 7244浮点错7250段违例7中断矢量单元和优先级 (2)中断响应:)中断响应: 如果中断的优先级大于系统处理机的优先级的话,如果中断的优先级大于系统处理机的优先级的话,中断就可以被相应。中断的优先级事先是由硬件接中断就可以被相应。中断的优先级事先是由硬件接线决定的,但中断被接受以后,处理机优先级将由线决定的,但中断被接受以后,处理机优先级将由存放在中断矢量单元的存放在中断矢量单元的PS决定,操作系统还能

64、够随决定,操作系统还能够随时改变其中的内容。时改变其中的内容。 (3)中断处理及返回:)中断处理及返回: 系统根据中断矢量的内容调用相应的中断处理程系统根据中断矢量的内容调用相应的中断处理程序,不同的中断源的处理会有很大的不同。处理完序,不同的中断源的处理会有很大的不同。处理完毕后返回,然后系统核执行一系列特殊机器指令,毕后返回,然后系统核执行一系列特殊机器指令,恢复前一上下文层的寄存器上下文和核心栈,让它恢复前一上下文层的寄存器上下文和核心栈,让它们和中断发生时的情况一样,并恢复该上下文层的们和中断发生时的情况一样,并恢复该上下文层的运行,使得进程就像从来没有发生过中断一样继续运行,使得进程

65、就像从来没有发生过中断一样继续运行。运行。中断优先级中断优先级 在处理机的状态字在处理机的状态字PSL中,第中,第2016位表示处理机的优先位表示处理机的优先级,共级,共5个二进制位,故硬件可识别的中断有个二进制位,故硬件可识别的中断有32种(种(001FH,其中优先级其中优先级00最低)。最低)。00被用于所有用户态的程序和大被用于所有用户态的程序和大部分的操作系统代码,之后的部分的操作系统代码,之后的15个(个(010FH)是软件中断,)是软件中断,最高的最高的16个级别(个级别(10-1FH)用于硬件中断。)用于硬件中断。 由于不同的事件可能引发中断,所以一个中断可能在一个由于不同的事件

66、可能引发中断,所以一个中断可能在一个中断被服务时发生。中断被服务时发生。UNIX系统对这种需求的方法是将中断分系统对这种需求的方法是将中断分为不同的优先级(为不同的优先级(interrupt priority level 简称简称ipl),并允),并允许高优先级的中断可抢占低优先级的中断服务程序。许高优先级的中断可抢占低优先级的中断服务程序。 这样,当中断发生时,如果它的这样,当中断发生时,如果它的ipl高于当前的高于当前的ipl,处理,处理就被挂起,并调用新的中断处理程序,中断处理程序在新的就被挂起,并调用新的中断处理程序,中断处理程序在新的ipl上开始执行。当处理程序结束时,上开始执行。当

67、处理程序结束时,ipl降低为上一个值(这降低为上一个值(这个值通过保存在中断栈上的旧处理器状态字取得),内核恢个值通过保存在中断栈上的旧处理器状态字取得),内核恢复被中断的进程。当内核收到比当前复被中断的进程。当内核收到比当前ipl低的中断,此中断不低的中断,此中断不被立即处理,而是存储在中断寄存器中,当被立即处理,而是存储在中断寄存器中,当ipl降到足够低时,降到足够低时,这个保存的中断再重新处理。这个保存的中断再重新处理。 否否是是处理中断并返回 从保存的PSW中恢复ipl可以恢复某些被阻塞的中断吗?返回到正常的处理过程中断到达新ipl旧ipl创建新一层上下文,将PC和PSW压栈,将新ip

68、l置为当前ipl,并且调用中断处理程序。将中断保存在特殊的寄存器中在处理机ipl降到足够低之前阻塞恢复恢复被阻塞的优先级最高的中断4.7.2 4.7.2 时钟中断处理时钟中断处理 时钟中断可归入硬件中断的类中,但由于时钟中断可归入硬件中断的类中,但由于和其他的硬件中断不甚相同,所以把它单独和其他的硬件中断不甚相同,所以把它单独列出来说明。列出来说明。 (1)时钟中断)时钟中断clock处理来自线频时钟或可处理来自线频时钟或可编程实时时钟的中断,其优先级仅次于电源编程实时时钟的中断,其优先级仅次于电源失效,因而虽然它的中断处理程序任务多,失效,因而虽然它的中断处理程序任务多,也要处理的尽可能快。

69、首先我们先介绍一下也要处理的尽可能快。首先我们先介绍一下时标的概念。时标的概念。 时标:是指两次连续的时钟中断之间间隔时标:是指两次连续的时钟中断之间间隔的时间,称为的时间,称为CPU tick或或clock tick。但是系。但是系统一般用统一般用HZ来标识,如果时标为来标识,如果时标为10ms,则,则HZ为为100。 (2)时钟中断的功能:)时钟中断的功能:在需要时重整硬件时钟;在需要时重整硬件时钟;对当前运行的进程更新对当前运行的进程更新CPU的使用统计;的使用统计;执行有关调度的函数,如计算优先级、时间片超时执行有关调度的函数,如计算优先级、时间片超时处理;处理;如果当前进程超过分配给

70、它的如果当前进程超过分配给它的CPU时限,向该进程时限,向该进程发送发送SIGXCPU的信号;的信号;更新日时钟和其他相关的时钟更新日时钟和其他相关的时钟处理调出队列;处理调出队列;在恰当的时候调用系统调用,如对换进程和页面管在恰当的时候调用系统调用,如对换进程和页面管理进程;理进程; 需要注意的一点是,以上的任务不需要在每个时需要注意的一点是,以上的任务不需要在每个时钟时标都处理,大多数钟时标都处理,大多数UNIX系统指定一个主时标系统指定一个主时标(major tick),对于一些任务,只需在主时标时才),对于一些任务,只需在主时标时才执行它们。执行它们。 否是重启时钟中断callout数

71、组有函数?降低处理机的优先级为5执行callout数组中已到执行时间的各个操作,并将未到期的部分向数组头部移动更新callout中第一个非零时间值根据中断前是用户态还是核心态,计算u.u_time或者u.u_stime并累计p_cpu时钟累计到1m?更新lbolt,系统累计时间加1对所有进程做:驻留时间加1、计算其p_cpu时间和优先级每隔4s,重设runrun标志,唤醒因lbolt的所有进程若runin设置,则唤醒调度进程若前状态是用户态,判断是否收到信号,有就执行信号处理程序返回是否4.7.3 4.7.3 捕俘(自陷)捕俘(自陷)-trap-trap 1) 1) 按照处理机前状态及按照处理

72、机前状态及捕俘原因原因UNIX将将捕俘分成三类:分成三类:核心态。核心态。用户态,并非由用户态,并非由“trap”指令造成的陷入。指令造成的陷入。用户态,由用户态,由“trap”指令造成的陷入。指令造成的陷入。流程图(见流程图(见word文档):文档):4.7.4 4.7.4 系统调用系统调用系统可以通过使用系统提供的一组广义指令,系统可以通过使用系统提供的一组广义指令,向系统提出各种资源请求,或对自己的进程向系统提出各种资源请求,或对自己的进程进行管理和控制。在进行管理和控制。在UNIX中把这样的广义指中把这样的广义指令称为系统调用。令称为系统调用。系统调用是用户程序取得操作系统服务的唯系统

73、调用是用户程序取得操作系统服务的唯一方式,是用户程序与系统核心之间仅有的一方式,是用户程序与系统核心之间仅有的接口。在接口。在UNIX系统中规定,用户必须通过系统中规定,用户必须通过trap指令使用系统调用程序。指令使用系统调用程序。 1 系统调用入口表结构系统调用入口表结构 为使系统调用能方便地转至相应的系统处为使系统调用能方便地转至相应的系统处理程序理程序,在系统中设置了一张系统调用入口表在系统中设置了一张系统调用入口表sysent。该表共有。该表共有64个表目,每个表目有两个表目,每个表目有两项:一项是系统调用自带参数个数,另一项项:一项是系统调用自带参数个数,另一项是系统调用处理程序的

74、入口地址。是系统调用处理程序的入口地址。结构如下:结构如下:struct sysent int count; int (*call)(); sysent64;int sysent /*参数个数参数个数 入口地址入口地址*/ 0, &nullsys, /*0=indir*/ 0, &rexit, /*1=exit*/ 0, &fork, /*2=fork*/ 2, &read, /*3=read*/ 2, &write, /*4=write*/ . . . . . . 0, &nosys /*63=x*/;UMODE?dev+8dev=?6+user: trap指令9+user: 段违例8: 浮

75、点错default:电源失效程序中断0+user: 总线超时1+user: 非法指令2+user: bpt-跟踪3+user: iot5+user: 仿真陷入8+user: 浮点错出错?psignal()psig恢复成功扩展成功结 束issigpsignal直接返回panic不 返 回执行相应的系统调用核心态用户态非”trap”造成用户态非”trap”造成nyynnyny2 2 系统调用的方式系统调用的方式每当进程执行一条系统调用时,都将执行一每当进程执行一条系统调用时,都将执行一条系统调用陷入指令,以使进程由用户态变条系统调用陷入指令,以使进程由用户态变为核心态,并将一个唯一的系统调用传递给

76、为核心态,并将一个唯一的系统调用传递给核心核心,以报告该系统调用的类型。下图示出以报告该系统调用的类型。下图示出了系统调用的处理过程:了系统调用的处理过程:核心以系统调用号为索引,去查找系统调用核心以系统调用号为索引,去查找系统调用表,从中得到该系统调用子程序的入口地址。表,从中得到该系统调用子程序的入口地址。由于系统调用所提供的参数,通常是放在用由于系统调用所提供的参数,通常是放在用户栈中,因此核心要先算出第一个参数在用户栈中,因此核心要先算出第一个参数在用户栈中的地址。户栈中的地址。执行该系统调用子程序。执行该系统调用子程序。检查是否有错。检查是否有错。 流程图见流程图见word4.7.2

77、 4.7.2 软中断处理软中断处理 (1)软件中断(或称)软件中断(或称“信号信号”)是一种特殊的进程间通信)是一种特殊的进程间通信的机制,在产生的机制,在产生“坏消息坏消息”时使用。软件中断通知进程发生时使用。软件中断通知进程发生了异步事件。在系统了异步事件。在系统V中有中有20个软中断信号,分为下列几类:个软中断信号,分为下列几类:与进程终止相关的软中断信号。与进程终止相关的软中断信号。与进程例外事件相关的软中断信号。与进程例外事件相关的软中断信号。与在系统调用期间遇到的不可恢复的条件相关的软中断信号。与在系统调用期间遇到的不可恢复的条件相关的软中断信号。由在执行一个系统调用期间遇到的非预

78、测性错误条件所引起由在执行一个系统调用期间遇到的非预测性错误条件所引起的软中断信号。的软中断信号。由在用户态下的进程发出的软中断信号。由在用户态下的进程发出的软中断信号。跟踪进程执行的软中断信号。跟踪进程执行的软中断信号。只有当一个进程即将从内核态返回用户态时,或者它要进入只有当一个进程即将从内核态返回用户态时,或者它要进入或离开一个适当的低调度优先级睡眠状态时,内核才要检查或离开一个适当的低调度优先级睡眠状态时,内核才要检查它是否收到了一个软中断信号。而内核只当一个进程从内核它是否收到了一个软中断信号。而内核只当一个进程从内核态返回用户态时才处理软中断信号。态返回用户态时才处理软中断信号。(

79、2)软件中断的启动、处理)软件中断的启动、处理 a.设置期望动作设置期望动作 在每个进程的在每个进程的ppda区中有一个整型数组区中有一个整型数组“u.u_signal”,其长度为,其长度为“NSIG”,其中每一项,其中每一项对应于一个不同类型的软中断,并定义了该进程遇对应于一个不同类型的软中断,并定义了该进程遇到此中断时应采取的动作。而每个进程都可以设置到此中断时应采取的动作。而每个进程都可以设置自己的自己的“u.u_signal”。系统调用。系统调用“ssig”实现实现这个功能:设置数组这个功能:设置数组“u.u_signal”中一个元素的中一个元素的值。值。 b. 对进程造成中断对进程造

80、成中断 在进程在进程“proc”结构中包含有结构中包含有“p_sig”项,将项,将其设置为某一中断类型编号,就对该进程造就了一其设置为某一中断类型编号,就对该进程造就了一个中断。系统调用个中断。系统调用“kill(对指定标识号的进程造(对指定标识号的进程造成一指定的中断)成一指定的中断)”、“signal(对一个指定的终(对一个指定的终端所控制的或启动的所有进程造成一次指定的软件端所控制的或启动的所有进程造成一次指定的软件中断)中断)”、“psignal(实际设置(实际设置p_sig)”用以实用以实现这部分功能。现这部分功能。 c.中断处理中断处理 软件中断的作用不会立即产生,其规定动作总是软

81、件中断的作用不会立即产生,其规定动作总是由受影响的进程自己执行并施加到自身的。系统首由受影响的进程自己执行并施加到自身的。系统首先测试是否收到待处理的不可忽略软件中断,如是先测试是否收到待处理的不可忽略软件中断,如是则实现由软件中断触发的动作,最后返回。这里用则实现由软件中断触发的动作,最后返回。这里用到了系统调用到了系统调用“issig(测试当前进程是否接受到一(测试当前进程是否接受到一个等待处理的不可忽略中断)个等待处理的不可忽略中断)”、“psig(实现由(实现由软件中断触发的动作)软件中断触发的动作)”、“core(必要是实现内(必要是实现内存映像的转存)存映像的转存)”、“exit(

82、终止当亲活动进程)(终止当亲活动进程)”。总的处理流程见图。总的处理流程见图2。 需要知道的是,系统调用是在工作核心态的,那需要知道的是,系统调用是在工作核心态的,那么工作在用户态的进程如何实现系统调用呢?么工作在用户态的进程如何实现系统调用呢?UNIX系统采用的系统采用的“操作系统陷入操作系统陷入”使之成为可能。系统使之成为可能。系统采用一个预定义的函数库,其中的函数具有系统调采用一个预定义的函数库,其中的函数具有系统调用的名字,可以将进程的执行方式变为核心态,从用的名字,可以将进程的执行方式变为核心态,从而保证用户程序可以请求系统调用。而保证用户程序可以请求系统调用。 是否是否是是否否否是软中断发生调用ssig设置期望动作进程标识是否为0?找到所有被指定终端控制的进程找到所有进程标识相同的进程调用psignal为进程设置中断号进程会终止自身?进程被跟踪?进程会终止自身?stop()返回处理程序的地址返回0处理程序地址有效?实现软中断触发的动作恢复中断前的PS和PC调用内存映像存储EXIT()软中断处理流程图

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 工作计划

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号