第四章 UNIX的设备管理_第1页
第四章 UNIX的设备管理_第2页
第四章 UNIX的设备管理_第3页
第四章 UNIX的设备管理_第4页
第四章 UNIX的设备管理_第5页
已阅读5页,还剩74页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

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_wcoun

49、t=-256; (*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

50、=bdeswrbp-b_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)模块的内部的接口,行规则程序的作用是对输人和输出的数据进行解释。在标准方式(ca

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

52、第一个无效数据的位置。 7 14 g a 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的索引值,使以后的操作不再提取同一字符。如果提取操作移出的是某。bloc

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

54、 cblocks27 字符 0 8p i 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

55、 23 字符 0 8 0 8 0 7 0 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能接受更多数据的事件); c

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

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

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

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

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

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论