第1页:13.6 设备管理
- 打开一个设备文件即相当于申请对应的设备,如该设备已处于打开状态则等待
- 关闭一个设备文件即相当于释放对应的设备,如有等待者则唤醒一个
- 读写一个设备文件就相当于对所对应的设备执行I/O操作
第2页:缓冲与缓存
- 缓冲与缓存
- 块型设备缓冲
- 用于磁盘、磁带等设备的I/O传输
- 每个缓冲区的长度与块型物理设备中一个块的长度相同,即为512字节
- 缓冲区为所有块型设备公用,其总数为15个
第3页:缓冲与缓存(续)
块型设备缓冲structbuf{intb_flags;structbuf*b_forw;structbuf*b_back;structbuf*av_forw;structbuf*av_back;intb_dev;intb_wcount;char*b_addr;char*b_xmem;char*b_blkno;charb_error;char*b_resid;}buf[NBUF];
第4页:缓冲与缓存(续3)
块型设备控制结构structdevtab{chard_active;chard_erncnt;structbuf*b_forw;structbuf*b_back;structbuf*d_actf;structbuf*d_actl;}
第5页:缓冲与缓存(续4)
块缓冲数据读写内存区缓冲区磁盘块iomovebread,breadabwrite,bawrite,bdwrite
第6页:字符型设备缓冲
- 字符型设备缓冲
- 缓冲池structcblock{structcblock*c_next;charinfo[6];}
- 读操作
- 写操作
第7页:预先读与延迟写
- 预先读与延迟写
- 预先读(read ahead)
- 将以后即将使用的块读入缓冲区中
- 以后进程需要该块时便可在缓冲区中直接得到,不必等待设备I/O传输
- 基于文件顺序访问的假设
- 预先读函数breada(dev,blkno,rablkno)
- rablkno链入d链
- IO完成放入b链和av链
第8页:预先读与延迟写(续)
- 预先读与延迟写
- 延迟写(delayed write)
- 当一个缓冲块尚未写满时,暂不将其写到外存
- 以后继续写时,不必将该块由外存读入内存
- 延迟写函数bdwrite(bp)
- 将bp对应的缓冲区链入b链和av链,若以后还需要读写,可在缓冲区中得到.
- 缓冲区在av链上取到用作其它用途前,由b链换到d链,写回外存.
第9页:13.7 系统调用
- 地位–操作系统API–One of Programmer Interface
- The other beingSystem Libs
- 主要包括–Process manipulation–File manipulation–Communication–Others
第10页:13.7.1 有关进程的系统调用命令
- 相关系统调用
- 创建子进程
- Pid=fork()
- 子进程是父进程的复制品
- 返回值:父进程为子进程编号,子进程为0
- 加载并执行新程序
- execl(prog, arg0,…,argn-1,0)
- 以arg0,…,argn-1为参数执行prog
- 覆盖原来程序,从第一条指令开始执行
第11页:13.7.1 有关进程的系统调用…(续)
- 进程自我结束
- exit(status)
- Status为终止状态
- 唤醒父进程
- 等待子进程终止
- pid=wait(&status)
- 返回终止子进程编号
- 参数为子进程的终止状态
第12页:13.7.1 有关进程的系统调用
proc结构p_pid=9p_ppid=5user结构pid = fork();if(pid == 0) {}else{}…proc结构p_pid=12p_ppid=9user结构复制父进程子进程fork()创建子进程联系子进程号(>0整数)pid = fork();if(pid == 0) {}else{}…恒为0
第13页:13.7.1 有关进程的系统调用(续)
pid=fork();if(pid==0) {execl(“P”,0);}else{}…proc结构p_pid=9p_ppid=5user结构pid=fork();if(pid==0) {execl(“P”,0);}else{}…proc结构p_pid=12p_ppid=9user结构父进程子进程execl()加载并执行新程序
第14页:13.7.1 有关进程的系统调用(续3)
pid=fork();if(pid==0) {execl(“P”,0);}else{}…proc结构p_pid=9p_ppid=5user结构程序P(覆盖原来程序)proc结构p_pid=12p_ppid=9user结构父进程子进程execl()加载并执行新程序
第15页:13.7.1 有关进程的系统调用(续4)
pid=fork();if(pid==0) {execl(“P”,0);}else{id=wait(&s)}…proc结构p_pid=9p_ppid=5user结构程序P (覆盖原来程序)exit(2)proc结构p_pid=12p_ppid=9user结构父进程子进程exit()进程自我终止
第16页:13.7.1 有关进程的系统调用(续5)
P1P2 P3 P4P5 P6P7P8例子:设有8个程序,执行次序如下图所示,试用fork,execl,wait,exit系统调用描述之.
第17页:13.7.1 有关进程的系统调用(续6)
main(){intpid1,pid2,pid3,pid4,pid5,pid6,pid7,pid8;intend_p1=end_p2=end_p3=end_p4=end_p5=…=end_p8=0;intpid,status;if((pid1=fork())==0)execl("P1",0);wait(&status);if((pid2=fork())==0)execl("P2",0);if((pid3=fork())==0)execl("P3",0);if((pid4=fork())==0)execl("P4",0);do{//等待P2结束pid=wait(&status);if(pid==pid2)end_p2=1;if(pid==pid3)end_p3=1;if(pid==pid4)end_p4=1;}while(end_p2==0);
第18页:13.7.1 有关进程的系统调用(续7)
if((pid5=fork())==0)execl("P5",0);if((pid6=fork())==0)execl("P6",0);do{//等待P3和P6结束pid=wait(&status);if(pid==pid3)end_p3=1;if(pid==pid4)end_p4=1;if(pid==pid5)end_p5=1;if(pid==pid6)end_p6=1;}while(end_p3==0||end_p6==0);if((pid7=fork())==0)execl("P7",0);do{//等待P4,P5,P7结束pid=wait(&status);if(pid==pid4)end_p4=1;if(pid==pid5)end_p5=1;if(pid==pid7)end_p7=1;}while(end_p4==0||end_p5==0||end_p7==0);if((pid8=fork())==0)execl("P8",0);wait(&status);exit(0);}
第19页:vfork与fork
- vfork与fork
- fork功能
- 复制地址空间(code+data+stack)
- 复制控制结构(proc,user)
- 特点
- 父子进程之间有两个各自独立的数据拷贝
- 问题
- 不加载新程序
- 不能实现数据共享,不能描述诸如“有界缓冲区”问题
- 若加载新程序
- 复制没有意义,浪费时间和空间
第20页:vfork与fork(续)
- vfork与fork
- vfork
- 只复制控制结构(proc+user);
- 不复制地址空间(code+data)
- 父子进程共享地址空间
- 使用
- 父进程使用vfork创建子进程;
- 子进程与父进程共享地址空间;
- 子进程使用execve改变其虚拟地址空间.
第21页:13.7.2 有关文件的系统调用命令
- 创建文件fd=creat(path_name,mode)
- 分配一个inode
- 填写目录项
- 以写方式打开该文件
- 返回文件描述符
- 打开文件fd=open(path_name,mode)
- 查目录找到inode
- 权限检查(mode, i_mode, i_uid, i_gid, u_uid,u_gid)
- 在file表中分配一个表项,指向该内存inode
- 在u_ofile中取一表目,指向file表中对应表目
- 返回文件描述符fd
第22页:有关文件的系统调用命令
- 有关文件的系统调用命令
- 关闭文件close(fd)
- 由fd查u_ofile找到对应入口
- 由u_ofile[fd]找到file表对应入口
- f_count--
- 若f_count=0, i_count–
- 若i_count=0,且i_node修改过, i_node写回外存
- u_ofile[fd]=-1(空闲标志)
第23页:有关文件的系统调用命令(续)
- 有关文件的系统调用命令
- 读命令n_rd=read(fd,buf,bytes)
- 由u_ofile[fd],找到file表对应入口
- 检查访问权限(f_flag, READ)
- 由f_inode找到内存inode入口
- 由f_offset, count和i_addr计算磁盘块号(可能多个块)(bmap函数)
- 启动I/O设备读取盘块到系统缓冲区中(如buffer无,切换进程)
- 缓冲区信息复制到进程空间(iomove)
- 返回实际传输字节数nrd
第24页:有关文件的系统调用命令(续3)
- 有关文件的系统调用命令
- 写文件n_wt=write(fd,buf,bytes)
- 由u_ofile[fd],找到file表对应入口
- 检查访问权限(f_flag, WRITE)
- 由f_inode找到内存inode入口
- 由f_offset, count和i_addr计算磁盘地址块号(可能分配盘块)
- 申请系统缓冲区,将buf起始count数据送到缓冲区中(可多次)
- 缓冲区链到设备I/O链上,如设备空闲启动设备
- 修改inode中文件长度i_size
- 返回实际传输字节数nwt
第25页:有关文件的系统调用命令(续4)
- 有关文件的系统调用命令
- 文件指针定位seek(fd,offset,origin)
- 由u_ofile[fd]找到file表入口
- 由f_inode找到内存inode
- 检查参数合法性(i_size0, i_size1,f_offset, offset)
- 按参数要求调整f_offset指针
第26页:有关文件的系统调用命令(续5)
- 有关文件的系统调用命令
- 建立文件链接link(old_name,new_name)
- 查目录找到oldpathname(inode)
- 查目录找到newpathname的末级目录
- 检查操作合法性
- Inode的i_nlink++
- (name, i_number)末级目录
- 断开文件链接unlink(path_name)
- 查目录找到pathname(inode)
- i_nlink--;如结果为0,释放所有磁盘块(删除文件)
- 清除末级文件名在末级目录中的登记
第27页:有关文件的系统调用命令(续6)
- 有关文件的系统调用命令
- 建立管道pipe(fd)
- 分配一个inode,(i_flag标志为PIPE文件,i_count=2)
- 分配2个file表目(f_flag分别为R和W,读/写指针为0)
- 分配2个u_ofile表目,分别指向2个file表目
- 返回2个文件描述符fd[0],fd[1],分别为u_ofile中的2个入口
第28页:有关文件的系统调用命令(续7)
- 有关文件的系统调用命令
- 安装文件卷smount( )
- 检查是否超级用户
- 找到special_pathname文件的inode(用makenode建立)
- 合法性检查(特殊块型文件)
- 找到directory_pathname节点的inode
- 如非目录或引用数大于1,错返
- 读入super block到buf,按filesys格式解释
- 分配一个mount表项,填写(m_dev,m_bufp,m_inodep)
- 安装节点inode的i_addr[0]=设备文件i_addr[0]
- 安装节点inode的i_flag =| IMOUNT
第29页:有关文件的系统调用命令(续8)
- 有关文件的系统调用命令
- 卸下文件卷sumount(special_name)
- 查目录找到special_pathname的inode,取dev(i_addr[0])
- 释放特殊文件的inode
- 由dev查mount表(m_dev)找到对应super block
- 系统缓冲区延迟写块写回
- 该卷所有更新inode写回
- super block写回
- 释放super block所占用的缓冲区
- 由m_inodep找到安装节点的inode
- 安装节点i_flag =& ~IMOUNT
- 释放mount表项
第30页:13.8 外壳语言
- 一般命令
- 由命令名和空格分隔的若干个参数所组成
- 后台命令
- 在一般命令之后加上一个符号“&”,即成为后台命令
- 输入输出重新定向
- 用文件来取代标准输入设备或标准输出设备称作I/O重新定向
- 用符号“<”,“<<”,“>”,“>>”分别表示输入重新定向和输出重新定向
第31页:13.8 外壳语言(续)
- 管道线与过滤器
- 利用管道文件pipe可以实现管道线和过滤器
- 符号“|”在UNIX系统中被称作管道符
- 可以将两个或多个shell命令串联在一起
- 前一个命令的标准输出作为后一个命令的标准输入
- 实现
- 为每个管道符创建一个pipe文件