操作系统实验指导书14级

更新时间:2023-09-27 20:35:02 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

《操作系统原理》实验指导书

《操作系统原理》

实验指导书

-1-

《操作系统原理》实验指导书

目 录

实验一 UNIX/LINUX及其使用环境 ...................................... 3 实验二 进程的创建 ................................................................. 15 实验三 处理器调度 ................................. 错误!未定义书签。 实验四 进程互斥 ..................................................................... 19 实验五 信号机制 ..................................................................... 22 实验六 实验七 实验八 实验九

进程的管道通信 ......................................................... 26 消息的发送与接收 ..................... 错误!未定义书签。 存储管理 ..................................................................... 29 文件管理 ..................................................................... 37

-2-

《操作系统原理》实验指导书

实验一 UNIX/LINUX及其使用环境

(一)UNIX常用命令简介

[实验目的]

1、了解UNIX的命令及使用格式。

2、熟悉UNIX/LINUX的常用基本命令。 [实验学时] 2学时

[实验类型] 验证性

[实验内容]

1、通过WINDOWS操作系统中的远程登录程序telnet.exe 登录UNIX。

2、熟悉UNIX/LINUX的常用基本命令如ls、who、w、pwd、ps、pstree、top等。 3、通过WINDOWS操作系统中的FTP程序,练习WINDOWS和UNIX之间的文件交换。 [实验步骤]

一、UNIX的登录与退出

1、登录

在DOS环境下用MS提供的telnet程序(也可使用WINDOWS 自带的telnet图形界面程序或多功能的S-Term终端程序),可使PC作为终端(terminal)登录(login)UNIX服务器(UNIX Server)。

(1)执行格式:

telnet hostname(主机名)

或 telnet 主机的IP地址

例: telnet www.yahoo.com telnet 140.122.77.120 (2)步骤

login: (输入username) password: (输入密码)

2、退出

在UNIX系统提示符$下,输入logout、exit或shutdown 。

例:$ logout 二、UNIX命令格式

命令 [选项] [处理对象]

例:ls -la mydir 注意:(1)命令一般是小写字串。注意大小写有别

(2)选项通常以减号(-)再加上一个或数个字符表示,用来选择一个命令的不同操作

(3)同一行可有数个命令,命令间应以分号隔开

(4)命令后加上&可使该命令后台(background)执行 三、常用命令

1、目录操作 和DOS相似,UNIX采用树型目录管理结构,由根目录(/)开始一层层将子目录建下去,各子目录以 / 隔开。用户login后,工作目录的位置称为 home directory,由系统管理员设定。?~‘符号代表自己的home directory,例如 ~/myfile 是指自己home目录下myfile这个文件。

UNIX的通配符有三种:‘*‘ 和 ‘?‘ 用法与DOS相同, ?-? 代表区间内的任一字符,如test[0-5]即代表test0,test1,??,test5的集合。

-3-

《操作系统原理》实验指导书

(1)显示目录文件 ls

执行格式: ls [-atFlgR] [name] (name可为文件或目录名称) 例: ls 显示出当前目录下的文件

ls -a 显示出包含隐藏文件的所有文件 ls -t 按照文件最后修改时间显示文件 ls -F 显示出当前目录下的文件及其类型

ls -l 显示目录下所有文件的许可权、拥有者、文件大小、修改时间及名

ls -lg 同上

ls -R 显示出该目录及其子目录下的文件

注:ls与其它命令搭配使用可以生出很多技巧(最简单的如\,更多用法请输入ls --help查

看,其它命令的更多用法请输入 命令名 --help 查看.

(2)建新目录 mkdir

执行格式: mkdir directory-name

例: mkdir dir1 (新建一名为dir1的目录) (3)删除目录 rmdir

执行格式: rmdir directory-name 或 rm directory-name 例:rmdir dir1 删除目录dir1,但它必须是空目录,否则无法删除 rm -r dir1 删除目录dir1及其下所有文件及子目录

rm -rf dir1 不管是否空目录,统统删除,而且不给出提示,使用时要小心

(4) 改变工作目录位置 cd

执行格式: cd [name]

例: cd 改变目录位置至用户login时的working directory cd dir1 改变目录位置,至dir1目录

cd ~user 改变目录位置,至用户的working directory cd .. 改变目录位置,至当前目录的上层目录 cd ../user 改变目录位置,至上一级目录下的user目录

cd /dir-name1/dir-name2 改变目录位置,至绝对路径(Full path) cd - 回到进入当前目录前的上一个目录

(5)显示当前所在目录pwd 执行格式: pwd (6)查看目录大小du

执行格式: du [-s] directory

例: du dir1 显示目录dir1及其子目录容量(以kb为单位) du -s dir1 显示目录dir1的总容量 (7)显示环境变量

echo $HOME 显示家目录

echo $PATH 显示可执行文件搜索路径

env 显示所有环境变量(可能很多,最好用\grep PATH\等)

(8)修改环境变量,在bash下用export,如: export PATH=$PATH:/usr/local/bin

想知道export的具体用法,可以用shell的help命令:help export

-4-

《操作系统原理》实验指导书

2、文件操作

(1)查看文件(可以是二进制的)内容 cat

执行格式:cat filename或more filename 或cat filename|more

例: cat file1 以连续显示方式,查看文件file1的内容

more file1

或 cat file1|more 以分页方式查看文件的内容 (2)删除文件 rm

执行格式: rm filename

例: rm file?

rm f*

(3)复制文件 cp

执行格式: cp [-r] source destination

例: cp file1 file2 将file1复制成file2

cp file1 dir1 将file1复制到目录dir1

cp /tmp/file1 将file1复制到当前目录

cp /tmp/file1 file2 将file1 复制到当前目录名为file2

cp –r dir1 dir2 (recursive copy)复制整个目录。

(4)移动或更改文件、目录名称mv

执行格式: mv source destination

例: mv file1 file2 将文件file1,更名为file2

mv file1 dir1 将文件file1,移到目录dir1下

mv dir1 dir2

(5)比较文件(可以是二进制的)或目录的内容 diff

执行格式: diff [-r] name1 name2 (name1、name2同为文件或目录) 例: diff file1 file2 比较file1与file2的不同处

diff -r dir1 dir2 比较dir1与dir2的不同处

(6)文件中字符串的查找 grep 执行格式: grep string file

例: grep abc file1 查找并列出串abc所在的整行文字 (7)文件或命令的路径寻找

执行格式一:whereis command 显示命令的路径

执行格式二:which command 显示路径及使用者所定义的别名 执行格式三:whatis command 显示命令的功能摘要 执行格式四:find search -path -name filename -print

搜寻指定路径下某文件的路径

执行格式五:locate filename

根据系统预先生成的文件/目录数据库(/var/lib/slocate/slocate.db)查找匹配的文

件/目录,查找速度很快,如果有刚进行的文件改变而系统未到执行定时更新数据库的时间,可以打入updatedb命令手动更新. (8)建立文件或目录的链接 ln

例: ln source target1 建立source文件(已存在)的硬链接,命名为target1

ln -s source target2 建立source文件的符号链接,命名为target2

3、系统询问与权限口令 (1)查看系统中的使用者 执行格式: who (2)查看username

-5-

《操作系统原理》实验指导书

执行格式: who am I 查看自己的username (3)改变自己的username的帐号与口令 su 执行格式: su username

例: su username 输入帐号 password 输入密码

(4)文件属性的设置 chmod 改变文件或目录的读、写、执行的允许权

执行格式: chmod [-R] mode name

其中:[-R]为递归处理,将指定目录下所有文件及子目录一并处理

mode为3-8位数字,是文件/目录读、写、执行允许权的缩写(r:read,数字代号为\w:write,数字代号为\数字代号为\

mode: rwx rwx rwx user group other 缩写: (u) (g) (o)

例:chmod 755 dir1 将目录dir1设定成任何人皆有读取及执行的权利,但只有拥有者可

作写修改。其中7=4+2+1,5=4+1

chmod 700 file1 将file1设为拥有者可以读、写和执行 chmod o+x file2 将file2,增加拥有者可执行的权利

chmod g+x file3 将file3,增加组使用者可执行的权利 chmod o-r file4 将file4,除去其它使用者可读取的权利

(5)改变文件或目录所有权 chown

执行格式: chown [-R] username name

例: chown user file1 将文件file1改为user所有 chown .fox file1 将文件file1改为fox组所有

chown user.fox file1 将文件file1改为fox组的user所有

chown -R user dir1 将目录dir1及其下所有文件和子目录,改为user 所有

(6)检查用户所在组名称 groups 执行格式: groups

(7)改变文件或目录的组拥有权 chgrp

执行格式: chgrp [-R] groupname name

例: chgrp vlsi file1 将文件file1改为vlsi组所有

chgrp -R image dir1 将目录dir1及其下所有文件和子目录,改为image群组

(8)改变文件或目录的最后修改时间 touch 执行格式: touch name 4、进程操作

(1)查看系统目前的进程 ps 执行格式: ps [-aux]

例: ps 或ps -x 查看系统中属于自己的process

ps -au 查看系统中所有使用者的process

ps -aux 查看系统中包含系统内部及所有使用者的process

ps -aux|grep apache 找出系统中运行的所有名称中带有\串的

process

-6-

《操作系统原理》实验指导书

(2)查看正在background中执行的process 执行格式: jobs

(3)结束或终止进程 kill

执行格式: kill [-9] PID (PID为利用ps命令所查出的process ID) 例: kill 456

或 kill -9 456 终止process ID 为456的process (4)后台(background)执行process command的命令

执行格式: command & (在命令后加上 &) 例: gcc file1 & 在后台编译file1.c

注意:按下^Z,暂停正在执行的process。键入‖bg‖,将所暂停的process置入background中继续执行。

例: gcc file1 & ^Z stopped bg

(5)结束或终止在background中的进程 kill 执行格式: kill %n

例: kill %1 终止在background中的第一个job kill %2 终止在background中的第二个job (6)显示系统中程序的执行状态

例: top -q 不断地更新、显示系统程序的执行状态

第一行显示的项目依次为当前时间、系统启动时间、当前系统登录用户数目、平均负载。

第二行为进程情况,依次为进程总数、休眠进程数、运行进程数、僵死进程数、终止进程数。 第三行为CPU状态,依次为用户占用、系统占用、优先进程占用、闲置进程占用。

第四行为内存状态,依次为平均可用内存、已用内存、空闲内存、共享内存、缓存使用内存。 第五行为交换状态,依次为平均可用交换容量、已用容量、闲置容量、高速缓存容量。

PID 每个进程的ID。

PPID 每个进程的父进程ID。 UID 每个进程所有者的UID 。 USER 每个进程所有者的用户名。 PRI 每个进程的优先级别。 NI 该进程的优先级值。

SIZE 该进程的代码大小加上数据大小再加上堆栈空间大小的总数。单位是KB。 TSIZE 该进程的代码大小。对于内核进程这是一个很奇怪的值。 DSIZE 数据和堆栈的大小。 TRS 文本驻留大小。

D 被标记为―不干净‖的页项目。

LIB 使用的库页的大小。对于ELF进程没有作用。 RSS 该进程占用的物理内存的总数量,单位是KB。 SHARE 该进程使用共享内存的数量。

STAT 该进程的状态。其中S代表休眠状态;D代表不可中断的休眠状态;R代表运行状态;Z代表僵死状态;T代表停止或跟踪状态。

TIME 该进程自启动以来所占用的总CPU时间。如果进入的是累计模式,那么该时间还包括这个进程子进程所占用的时间。且标题会变成CTIME。

%CPU 该进程自最近一次刷新以来所占用的CPU时间和总时间的百分比。 %MEM 该进程占用的物理内存占总内存的百分比。

COMMAND 该进程的命令名称,如果一行显示不下,则会进行截取。内存中的进程会有一个完整的命令行 按\停止查看

(7)以树状图显示执行的程序 pstree

例: pstree -h 列出进程树并高亮标出当前执行的程序 (8)监视虚拟内存 vmstat

-7-

《操作系统原理》实验指导书

vmstat对系统的虚拟内存、进程、CPU活动进行监视,同时它也对磁盘和forks和vforks操作的个数进行汇总。 不足是:vmstat不能对某个进程进行深入分析,它仅是一对系统的整体情况进行分析。 例如:[angel@home /angel]# vmstat

procs memory swap io system cpu r b w swpd free buff cache si so bi bo in cs us sy id 0 0 0 7180 1852 56092 48400 0 0 6 5 24 8 0 0 18 其中: Procs

r: 等待运行的进程数 b: 处在非中断睡眠状态的进程数 w: 被交换出去的可运行的进程数。 Memory

swpd: 虚拟内存使用情况,单位:KB free: 空闲的内存,单位KB buff: 被用来做为缓存的内存数,单位:KB Swap

si: 从磁盘交换到内存的交换页数量,单位:KB/秒 so: 从内存交换到磁盘的交换页数量,单位:KB/秒 IO

bi: 发送到块设备的块数,单位:块/秒 bo: 从块设备接收到的块数,单位:块/秒 System

in: 每秒的中断数,包括时钟中断 cs: 每秒的环境(上下文)切换次数 CPU 按 CPU 的总使用百分比来显示

us: CPU 使用时间 sy: CPU 系统使用时间 id: 闲置时间

(9)分析共享内存、信号量和消息队列 ipcs(相关命令ipcrm:用于给有权限的用户清除这些量,注意不要乱清除,除非该量确实失效了) 例如:[angel@home /angel]# ipcs

------ Shared Memory Segments --------

key shmid owner perms bytes nattch status 0x00280267 0 root 644 1048576 1 0x61715f01 1 root 666 32000 33

0x00000000 2 nobody 600 92164 11 dest

------ Semaphore Arrays --------

key semid owner perms nsems status 0x00280269 0 root 666 14 0x61715f02 257 root 777 1

------ Message Queues --------

key msqid owner perms used-bytes messages

(10)监视用户空间程序发出的全部系统调用 strace

strace 还能显示调用的参数,以及用符号方式表示的返回值。

strace 从内核中接收信息,所以一个程序无论是否按调试方式编译(gcc -g)或是否被去掉了调试

信息,都可以被跟踪。

执行格式: strace [-tTeo] executable-program-name -t : 用来显示调用发生的时间 -T : 显示调用花费的时间 -e : 限定被跟踪的调用类型

-o : 将输出重定向到一个文件中

类似命令:ltrace [-fiS] executable-program-name

5、通信类

(1)本地工作站与UNIX服务器间的文件传输 ftp 执行格式: ftp 主机名

或 ftp 主机的IP地址

后续执行步骤:

-8-

《操作系统原理》实验指导书

name: password: ftp>help ftp>lcd dir1 ftp>get file1 ftp>put file2 ftp>!ls ftp>!pwd ftp>ls ftp>dir ftp>pwd

ftp>cd dir1 ftp>mget *.c ftp>mput *.txt ftp>quit ftp>bye

输入帐号 输入密码

显示ftp可使用的所有命令 改变本地机当前目录为dir1

将UNIX服务器文件file1拷到本地机 将本地文件file2,拷到UNIX服务器 显示本地机当前目录下所有文件 显示本地机当前所在目录下所有文件 显示UNIX服务器当前目录下所有文件 显示服务器当前目录下所有文件(略同于UNIX的 ls -l指令)

显示UNIX服务器当前所有目录位置 更改UNIX服务器的目录至dir1下 将服务器中 .c 文件拷到本地机中 将所有 .txt 文件拷贝到服务器 结束ftp工作 结束ftp工作

(2)检查与UNIX服务器连接是否正常 ping 执行格式: ping hostname

或 ping IP-Address

例: ping 127.1.1.1

(3)将文件当做E-mail的内容送出 mail

执行格式:mail -s ―Subjict-string‖ username@address

功能:将file.c当做mail的内容,送至user,subject name为program (4)传送E-mail给本地UNIX服务器上的用户 mail 执行格式: mail username (5)读取信件 mail 执行格式: mail

(6)列出套接字使用情况 socklist (7)查看网络连接 netstat

6、I/O命令

(1)管道(pipe-line)的使用

执行格式: command1|command2

功能:将command1的执行结果送到command2 作为输入

例: ls -R1|more 以分页方式列出当前目录文件及子目录名称 cat file1|more 以分页方式,列出file1的内容

(2)标准输入控制

执行格式: command-line

功能:将文件file1当作信件的内容,subject 名称为mail test 送给收信人 (3)标准输出控制

执行格式一: command>filename

功能:将command的执行结果送至指定的filename中

例: ls -l >list 将执行‖ls -l‖ 的结果写入文件list中

-9-

《操作系统原理》实验指导书

执行格式二: command>!filename

功能:同上,若filename文件已存在,则强迫重写 执行格式三: command>&filename

功能:将command执行所产生的任何信息写入filename 执行格式四:command>>filename

功能:将command 的执行结果,附加(append)到filename 执行格式五:command>>&filename

????????????功能:将command执行所产生的任何信息附加于filename中 7、其它常用命令

(1)命令在线帮助 man 执行格式: man command

例: man ls 查询ls这个指令的用法 (2)设定命令记录表长度 history 执行格式一: set history=n 例: set history=40

功能:设定命令记录表长度为40(可记载执行过的前面40个命令) 执行格式二: history 查看命令记录表的内容 (3)显示说明 info

执行格式: info command-name 例: info gcc

功能: 查看gcc的说明,按上下箭头选定菜单,回车进入,\键返回上级菜单. info不加参数则进入最上一级菜单.

四、用cat 命令查看 /proc 动态文件系统目录下的文件,辨识其中的系统信息. 例如: cat interrupts 列出当前中断占用情况

cat ioports 列出设备的硬件IO占用情况 cat pci 列出pci设备的情况 [实验报告要求]

1.调试说明。包括:调试情况,如上机时遇到问题及解决办法,观察到的现象及其分析,实验的心得体会,以及调试日期等需要记录的信息。

-10-

《操作系统原理》实验指导书

存器等;

3、系统级上、下文。包括OS为管理进程所用的信息,有静态和动态之分。 三、所涉及的系统调用

1、fork( ) 创建一个新进程。 系统调用格式:

pid=fork( )

参数定义:

int fork( )

fork( )返回值意义如下:

0:在子进程中,pid变量保存的fork( )返回值为0,表示当前进程是子进程。

>0:在父进程中,pid变量保存的fork( )返回值为子进程的id值(进程唯一标识符)。 -1:创建失败。

如果fork( )调用成功,它向父进程返回子进程的PID,并向子进程返回0,即fork( )被调用了一次,但返回了两次。此时OS在内存中建立一个新进程,所建的新进程是调用fork( )父进程(parent process)的副本,称为子进程(child process)。子进程继承了父进程的许多特性,并具有与父进程完全相同的用户级上下文。父进程与子进程并发执行。

核心为fork( )完成以下操作:

(1)为新进程分配一进程表项和进程标识符 进入fork( )后,核心检查系统是否有足够的资源来建立一个新进程。若资源不足,则fork( )系统调用失败;否则,核心为新进程分配一进程表项和唯一的进程标识符。

(2)检查同时运行的进程数目

超过预先规定的最大数目时,fork( )系统调用失败。 (3)拷贝进程表项中的数据

将父进程的当前目录和所有已打开的数据拷贝到子进程表项中,并置进程的状态为“创建”状态。

(4)子进程继承父进程的所有文件

对父进程当前目录和所有已打开的文件表项中的引用计数加1。 (5)为子进程创建进程上、下文

进程创建结束,设子进程状态为“内存中就绪”并返回子进程的标识符。 (6)子进程执行

虽然父进程与子进程程序完全相同,但每个进程都有自己的程序计数器PC(注意子进程的PC开始位置),然后根据pid变量保存的fork( )返回值的不同,执行了不同的分支语句。

例:

….. PC pid=fork( ); if (! pid) printf(\ else if (pid>0) printf(\

else

printf(\

……

fork( )调用前

-16-

《操作系统原理》实验指导书

fork( )调用后 PC ….. pid=fork( ); if (! pid) printf(\else if (pid>0) printf(\ else printf(\…… PC ….. pid=fork( ); if (! pid) printf(\else if (pid>0) printf(\ else printf(\……

四、参考程序

1、

#include main( ) {

int p1,p2;

while((p1=fork( ))= = -1); /*创建子进程p1*/ if (p1= =0) putchar('b'); else

{

while((p2=fork( ))= = -1); /*创建子进程p2*/ if(p2= =0) putchar('c'); else putchar('a'); }

} 2、

#include main( ) {

int p1,p2,i;

while((p1=fork( ))= -1); /*创建子进程p1*/ if (p1= =0)

for(i=0;i<10;i++)

printf(\ %d\\n\

else

{

while((p2=fork( ))= -1); /*创建子进程p2*/

if(p2= 0)

for(i=0;i<10;i++)

printf(\ %d\\n\

else

for(i=0;i<10;i++)

printf(\ %d\\n\

}

}

五、运行结果

1、bca,bac, abc ,??都有可能。 2、parent…

son…

-17-

《操作系统原理》实验指导书

daughter.. daughter.. 或 parent…

son… parent… daughter…等 六、分析原因

除strace 外,也可用ltrace -f -i -S ./executable-file-name查看以上程序执行过程。 1、从进程并发执行来看,各种情况都有可能。上面的三个进程没有同步措施,所以父进程与子进程的输出内容会叠加在一起。输出次序带有随机性。

2、由于函数printf( )在输出字符串时不会被中断,因此,字符串内部字符顺序输出不变。但由于进程并发执行的调度顺序和父子进程抢占处理机问题,输出字符串的顺序和先后随着执行的不同而发生变化。这与打印单字符的结果相同。

补充:进程树

在UNIX系统中,只有0进程是在系统引导时被创建的,在系统初启时由0进程创建1进程,以后0进程变成对换进程,1进程成为系统中的始祖进程。UNIX利用fork( )为每个终端创建一个子进程为用户服务,如等待用户登录、执行SHELL命令解释程序等,每个终端进程又可利用fork( )来创建其子进程,从而形成一棵进程树。可以说,系统中除0进程外的所有进程都是用fork( )创建的。 [思考问题]

(1)系统是怎样创建进程的?

(2)当首次调用新创建进程时,其入口在哪里?

[实验报告要求]

1.调试说明。包括:调试情况,如上机时遇到问题及解决办法,观察到的现象及其分析,对程序设计技巧的总结及分析等;程序的输出结果及对结果的分析;实验的心得体会,以及调试日期等需要记录的信息。

2.程序框图。

3.经教师签名的程序清单。

4.程序中使用的数据结构及符号说明。 5.程序运行时的初值和运行结果。

-18-

《操作系统原理》实验指导书

实验三 进程互斥

[实验目的]

1、进一步认识并发执行的实质

2、分析进程竞争资源的现象,学习解决进程互斥的方法

[实验学时] 2学时

[实验类型] 设计性

[实验内容]

1、修改实验(一)中的程序2,用lockf( )来给每一个进程加锁,以实现进程之间的互斥 2、观察并分析出现的现象 [实验步骤]

一、所涉及的系统调用

lockf(files,function,size)

用作锁定文件的某些段或者整个文件。 本函数的头文件为

#include \

参数定义:

int lockf(files,function,size) int files,function; long size;

其中:files是文件描述符;function是锁定和解锁:1表示锁定,0表示解锁。size是锁定或解锁的字节数,为0,表示从文件的当前位置到文件尾。 二、参考程序

#include #include main( ) {

int p1,p2,i;

while((p1=fork( ))= = -1); /*创建子进程p1*/

if (p1= =0) {

lockf(1,1,0); /*加锁,这里第一个参数为stdout(标准输出设备

的描述符)*/

for(i=0;i<10;i++)

printf(\

lockf(1,0,0); /*解锁*/ } else {

while((p2=fork( ))= =-1); /*创建子进程p2*/

if (p2= =0)

{

lockf(1,1,0); /*加锁*/

-19-

《操作系统原理》实验指导书

for(i=0;i<10;i++)

printf(\

lockf(1,0,0); /*解锁*/ }

else

{

lockf(1,1,0); /*加锁*/ for(i=0;i<10;i++)

printf(\ lockf(1,0,0); /*解锁*/

}

}

}

三、运行结果

parent… son… daughter.. daughter.. 或parent… son… parent… daughter…

大致与未上锁的输出结果相同,也是随着执行时间不同,输出结果的顺序有所不同。 四、分析原因

上述程序执行时,不同进程之间不存在共享临界资源(其中打印机的互斥性已由操作系统保证)问题,所以加锁与不加锁效果相同。 五、分析以下程序的输出结果:

#include #include main() {

int p1,p2,i; int *fp;

fp = fopen(\ ,\if(fp==NULL) {

printf(\ exit(-1); }

while((p1=fork( ))== -1); /*创建子进程p1*/ if (p1==0) {

lockf(*fp,1,0); /*加锁*/ for(i=0;i<10;i++)

fprintf(fp,\

lockf(*fp,0,0); /*解锁*/ } else {

while((p2=fork( ))==-1); /*创建子进程p2*/ if (p2==0) {

-20-

《操作系统原理》实验指导书

unsigned int s_free[NICFREE]; /*空闲块堆栈*/

unsigned int s_ninode; /*number of free inode in s_inode*/ unsigned short s_pinode; /*pointer of the sinode*/ unsigned int s_inode[NICINOD]; /*空闲i节点数*/

unsigned int s_rinode; /*remember inode*/ char s_fmod; /*超级块修改标志*/ };

struct pwd

{ unsigned short p_uid; unsigned short p_gid; char password[PWDSIZ]; };

struct dir

{ struct direct direct[DIRNUM];

int size; /*当前目录大小*/ };

struct hinode

{ struct inode *i_forw; /*hash表指针*/ };

struct file

{ char f_flag; /*文件操作标志*/ unsigned int f_count; /*引用计数*/

unsigned int f_inode; /*指向内存i节点*/

unsigned long f_off; /*read/write character pointer*/ };

struct user

{ unsigned short u_default_mode; unsigned short u_uid; unsigned short u_gid;

unsigned short u_ofile[NOFILE]; /*用户打开文件表*/ /*system open file pointer number */ };

extern struct hinode hinode[NHINO];

extern struct dir dir; /*当前目录(在内存中全部读入)*/ extern struct file sys_ofile[SYSOPENFILE];

extern struct filsys filsys; /*内存中的超级块*/ extern struct pwd pwd[PWDNUM]; extern struct user user[USERNUM];

extern FILE *fd; /* the file system column of all the system*/ extern struct inode *cur_path_inode; extern int user_id;

extern int iHave_formated;

extern int iCur_free_block_index;

/*proptype of the sub roution used in the file system*/ extern struct inode *iget( ); extern int iput( );

extern unsigned int balloc( ); extern bfree( );

extern struct inode *ialloc( ); extern ifree( );

extern unsigned int namei( ); extern unsigned short iname( ); extern unsigned int access( ); extern _dir( ); extern mkdir( ); extern chdir( );

-46-

《操作系统原理》实验指导书

extern unsigned short open( ); extern creat( );

extern unsigned int read( ); extern unsigned int write( ); extern int login( ); extern logout( ); extern install( ); extern format( ); extern close( ); extern halt( );

3、主程序main( ) (文件名 main.c)

主程序main.c用来测试文件系统的各种设计功能,其主要功能描述如程序设计中的第4部分。

#include \

#include \

struct hinode hinode[NHINO]; struct dir dir;

struct file sys_ofile[SYSOPENFILE]; struct filsys filsys; struct pwd pwd[PWDNUM]; struct user user[USERNUM]; FILE *fd;

struct inode *cur_path_inode; int user_id;

int iHave_formated;

int iCur_free_block_index; main( )

{ unsigned short ab_fd1,ab_fd2,ab_fd3,ab_fd4,ab_fd5; char *buf;

char file_content_buf[BLOCKSIZ]; char c;

printf(\

printf(\ if(getchar( )=='y')

printf(\ getchar();

if((c=getchar( ))=='y') { printf(\ format( ); iHave_formated = 1; printf(\ } else

printf(\ printf(\ install( );

printf(\ _dir( );

printf(\ login(2118,\ user_id=0;

printf(\ mkdir(\ _dir();

-47-

《操作系统原理》实验指导书

printf(\ chdir(\ _dir();

printf(\

ab_fd1=creat(2118,\ _dir();

printf(\

buf=(char *)malloc(BLOCKSIZ*6+5); printf(\

write(2118,ab_fd1,buf,BLOCKSIZ*6+5); printf(\ close(2118,ab_fd1);

printf(\ free(buf);

mkdir(\

printf(\ chdir(\

printf(\

ab_fd2=creat(2118,\ printf(\

buf=(char *)malloc(BLOCKSIZ*4+20); printf(\

write(2118,ab_fd2,buf,BLOCKSIZ*4+20); printf(\ close(2118,ab_fd2); free(buf);

printf(\ chdir(\

printf(\

ab_fd3=creat(2118,\ buf=(char *)malloc(BLOCKSIZ*10+255); write(2118,ab_fd3,buf,BLOCKSIZ*3+255); close(2118,ab_fd3); free(buf);

delete(\

printf(\

ab_fd4=creat(2118,\ buf=(char *)malloc(BLOCKSIZ*8+300); printf(\

write(2118,ab_fd4,buf,BLOCKSIZ*8+300); printf(\ close(2118,ab_fd4); free(buf);

printf(\

ab_fd3=open(2118,\ printf(\

buf=(char *)malloc(BLOCKSIZ*3+100); write(2118,ab_fd3,buf,BLOCKSIZ*3+100);

printf(\ close(2118,ab_fd3);

ab_fd5=creat(2118,\文件5\ write(2118,ab_fd5,\me to the moon\\nAnd let me play among the stars\\nLet me see what Spring is like\\nOn Jupiter and Mars\\n带我飞向月球,让我在群星中嬉戏,让我看看木星和火星上的春天\\n\

close(2118,ab_fd5);

ab_fd5=open(2118,\文件5\

-48-

《操作系统原理》实验指导书

read(2118,ab_fd5,file_content_buf,BLOCKSIZ);

printf(\读出文件5的内容: %s\\n\ close(2118,ab_fd5);

printf(\ free(buf); _dir( );

chdir(\

printf(\ logout(2118);

printf(\ halt( ); }

4、初始化磁盘格式程序format( ) (文件名format.c)

#include \#include \ format( )

{ struct inode *inode;

struct direct dir_buf[BLOCKSIZ/(DIRSIZ+2)]; struct pwd passwd[BLOCKSIZ/(PWDSIZ+4)]; /* {

{2116,03,\ {2117,03,\ {2118,04,\ {2119,04,\ {2220,05,\ }; */

//struct filsys;

unsigned int block_buf[BLOCKSIZ/sizeof(int)]; char *buf; int i,j;

/* creat the file system file */

memset(dir_buf,0,(BLOCKSIZ/(DIRSIZ+2))*sizeof(struct direct)); fd=fopen(\

buf=(char *)malloc((DINODEBLK+FILEBLK+2)*BLOCKSIZ*sizeof(char)); if (buf==NULL) exit(0);

printf(\ fseek(fd,0,SEEK_SET);

fwrite(buf,1,(DINODEBLK+FILEBLK+2)*BLOCKSIZ*sizeof(char),fd); /*0.initialize the passwd*/

passwd[0].p_uid=2116;passwd[0].p_gid=03; strcpy(passwd[0].password,\

passwd[1].p_uid=2117;passwd[1].p_gid=03; strcpy(passwd[1].password,\

passwd[2].p_uid=2118;passwd[2].p_gid=04; strcpy(passwd[2].password,\

passwd[3].p_uid=2119;passwd[3].p_gid=04; strcpy(passwd[3].password,\

passwd[4].p_uid=2220;passwd[4].p_gid=05; strcpy(passwd[4].password,\

/*给main()中的密码表pwd[PWDNUM]填入内容*/ pwd[0].p_uid=2116;pwd[0].p_gid=03; strcpy(pwd[0].password,\ pwd[1].p_uid=2117;pwd[1].p_gid=03;

-49-

《操作系统原理》实验指导书

strcpy(pwd[1].password,\ pwd[2].p_uid=2118;pwd[2].p_gid=04; strcpy(pwd[2].password,\ pwd[3].p_uid=2119;pwd[3].p_gid=04; strcpy(pwd[3].password,\ pwd[4].p_uid=2220;pwd[4].p_gid=05; strcpy(pwd[4].password,\

/*1.creat the main directory and its sub dir etc and the file password*/ inode=iget(0); /*0 empty dinode id */ inode->di_mode=DIEMPTY; iput(inode);

inode=iget(1); /*1 main dir id*/ inode->di_number=1;

inode->di_mode=DEFAULTMODE|DIDIR;

inode->di_size=3*sizeof(struct direct);

inode->di_addr[0]=0; /* block 0# is used by the main directory*/ strcpy(dir_buf[0].d_name,\ dir_buf[0].d_ino=1;

strcpy(dir_buf[1].d_name,\ dir_buf[1].d_ino=1;

strcpy(dir_buf[2].d_name,\ dir_buf[2].d_ino=2;

fseek(fd,DATASTART,SEEK_SET);

fwrite(dir_buf,1,3*sizeof(struct direct),fd); iput(inode);

inode=iget(2); /*2 etc dir id*/ inode->di_number=1;

inode->di_mode=DEFAULTMODE|DIDIR;

inode->di_size=3*sizeof(struct direct);

inode->di_addr[0]=1; /*block 1# is used by the etc directory*/ strcpy(dir_buf[0].d_name,\ dir_buf[0].d_ino=1;

strcpy(dir_buf[1].d_name,\ dir_buf[1].d_ino=2;

strcpy(dir_buf[2].d_name,\ dir_buf[2].d_ino=3;

fseek(fd,DATASTART+BLOCKSIZ*1,SEEK_SET);

fwrite(dir_buf,1,3*sizeof(struct direct),fd); iput(inode);

inode=iget(3); /*3 password id*/ inode->di_number=1;

inode->di_mode=DEFAULTMODE|DIFILE; inode->di_size=BLOCKSIZ;

inode->di_addr[0]=2; /* block 2# is used by the password file*/ for(i=5;i

strcpy(passwd[i].password,\ }

fseek(fd,DATASTART+2*BLOCKSIZ,SEEK_SET); fwrite(passwd,1,BLOCKSIZ,fd); iput(inode);

/*2.initialize the superblock*/ filsys.s_isize=DINODEBLK; filsys.s_fsize=FILEBLK;

filsys.s_ninode=DINODEBLK*BLOCKSIZ/DINODESIZ-4;

-50-

《操作系统原理》实验指导书

实验五 进程的管道通信

[实验目的]

1、了解什么是管道

2、熟悉UNIX/LINUX支持的管道通信方式 [实验学时] 2学时

[实验类型] 设计性

[实验内容]

编写程序实现进程的管道通信。用系统调用pipe( )建立一管道,二个子进程P1和P2分别向管道各写一句话:

Child 1 is sending a message! Child 2 is sending a message!

父进程从管道中读出二个来自子进程的信息并显示(要求先接收P1,后P2)。 [实验步骤] 一、什么是管道

UNIX系统在OS的发展上,最重要的贡献之一便是该系统首创了管道(pipe)。这也是UNIX系统的一大特色。

所谓管道,是指能够连接一个写进程和一个读进程的、并允许它们以生产者—消费者方式进行通信的一个共享文件,又称为pipe文件。由写进程从管道的写入端(句柄1)将数据写入管道,而读进程则从管道的读出端(句柄0)读出数据。

句柄fd[0] 读出端

句柄fd[1]

写入端

二、管道的类型:

1、有名管道

一个可以在文件系统中长期存在的、具有路径名的文件。用系统调用mknod( )建立。它克服无名管道使用上的局限性,可让更多的进程也能利用管道进行通信。因而其它进程可以知道它的存在,并能利用路径名来访问该文件。对有名管道的访问方式与访问其他文件一样,需先用open( )打开。

2、无名管道

一个临时文件。利用pipe( )建立起来的无名文件(无路径名)。只用该系统调用所返回的文件描述符来标识该文件,故只有调用pipe( )的进程及其子孙进程才能识别此文件描述符,才能利用该文件(管道)进行通信。当这些进程不再使用此管道时,核心收回其索引结点。

二种管道的读写方式是相同的,本文只讲无名管道。 3、pipe文件的建立

分配磁盘和内存索引结点、为读进程分配文件表项、为写进程分配文件表项、分配用户文件描述符

4、读/写进程互斥

内核为地址设置一个读指针和一个写指针,按先进先出顺序读、写。

为使读、写进程互斥地访问pipe文件,需使各进程互斥地访问pipe文件索引结点中的直接地址项。因此,每次进程在访问pipe文件前,都需检查该索引文件是否已被上锁。若是,

-26-

《操作系统原理》实验指导书

进程便睡眠等待,否则,将其上锁,进行读/写。操作结束后解锁,并唤醒因该索引结点上锁而睡眠的进程。

三、所涉及的系统调用

1、pipe( )

建立一无名管道。 系统调用格式

pipe(filedes) 参数定义

int pipe(filedes); int filedes[2];

其中,filedes[1]是写入端,filedes[0]是读出端。 该函数使用头文件如下:

#include #inlcude #include

2、read( ) 系统调用格式

read(fd,buf,nbyte)

功能:从fd所指示的文件中读出nbyte个字节的数据,并将它们送至由指针buf所指示的缓冲区中。如该文件被加锁,等待,直到锁打开为止。

参数定义

int read(fd,buf,nbyte); int fd; char *buf;

unsigned nbyte; 3、write( ) 系统调用格式

read(fd,buf,nbyte)

功能:把nbyte 个字节的数据,从buf所指向的缓冲区写到由fd所指向的文件中。如文件加锁,暂停写入,直至开锁。

参数定义同read( )。 四、参考程序

#include #include #include int pid1,pid2;

main( ) {

int fd[2];

char outpipe[100],inpipe[100];

pipe(fd); /*创建一个管道*/ while ((pid1=fork( ))= =-1); if(pid1= =0) {

lockf(fd[1],1,0);

sprintf(outpipe,\

/*把串放入数组outpipe中*/

write(fd[1],outpipe,50); /*向管道写长为50字节的串*/

-27-

《操作系统原理》实验指导书

sleep(5); /*自我阻塞5秒*/ lockf(fd[1],0,0); exit(0);

}

else

{

while((pid2=fork( ))= =-1); if(pid2= =0)

{ lockf(fd[1],1,0); /*互斥*/

sprintf(outpipe,\

write(fd[1],outpipe,50); sleep(5);

lockf(fd[1],0,0);

exit(0); }

else

{ wait(0); /*同步*/

read(fd[0],inpipe,50); /*从管道中读长为50字节的串*/

printf(\

wait(0);

read(fd[0],inpipe,50); printf(\

exit(0); } }

}

五、运行结果

延迟5秒后显示

child 1 process is sending message!

再延迟5秒

child 2 process is sending message! [思考问题]

1、程序中的sleep(5)起什么作用?

2、子进程1和2为什么也能对管道进行操作? [实验报告要求]

1.调试说明。包括:调试情况,如上机时遇到问题及解决办法,观察到的现象及其分析,对程序设计技巧的总结及分析等;程序的输出结果及对结果的分析;实验的心得体会,以及调试日期等需要记录的信息。

2.程序框图。

3.经教师签名的程序清单。

4.程序中使用的数据结构及符号说明。 5.程序运行时的初值和运行结果。

-28-

《操作系统原理》实验指导书

实验六 存储管理

[实验目的]

通过模拟实现请求页式存储管理的几种基本页面置换算法,了解虚拟存储技术的特点,掌握虚拟存储请求页式存储管理中几种基本页面置换算法的基本思想和实现过程,并比较它们的效率。 [实验学时] 4学时

[实验类型] 设计性

[实验内容]

设计一个虚拟存储区和内存工作区,并使用下述算法计算访问命中率。

1、最佳淘汰算法(OPT) 2、先进先出的算法(FIFO) 3、最近最久未使用算法(LRU) 4、最不经常使用算法(LFU) 5、最近未使用算法(NUR)

命中率=1-页面失效次数/页地址流长度

本实验的程序设计基本上按照实验内容进行。即首先用srand( )和rand( )函数定义和产生指令序列,然后将指令序列变换成相应的页地址流,并针对不同的算法计算出相应的命中率。

(1)通过随机数产生一个指令序列,共320条指令。指令的地址按下述原则生成: A:50%的指令是顺序执行的

B:25%的指令是均匀分布在前地址部分 C:25%的指令是均匀分布在后地址部分 具体的实施方法是:

A:在[0,319]的指令地址之间随机选取一起点m B:顺序执行一条指令,即执行地址为m+1的指令

C:在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为m‘ D:顺序执行一条指令,其地址为m‘+1

E:在后地址[m‘+2,319]中随机选取一条指令并执行 F:重复步骤A-E,直到320次指令 (2)将指令序列变换为页地址流 设:页面大小为1K;

用户内存容量4页到32页; 用户虚存容量为32K。

在用户虚存中,按每K存放10条指令排列虚存地址,即320条指令在虚存中的存放方式为:

第 0 条-第 9 条指令为第0页(对应虚存地址为[0,9]) 第10条-第19条指令为第1页(对应虚存地址为[10,19])

????????????

第310条-第319条指令为第31页(对应虚存地址为[310,319]) 按以上方式,用户指令可组成32页。

-29-

《操作系统原理》实验指导书

[实验步骤]

一、虚拟存储系统

UNIX中,为了提高内存利用率,提供了内外存进程对换机制;内存空间的分配和回收均以页为单位进行;一个进程只需将其一部分(段或页)调入内存便可运行;还支持请求调页的存储管理方式。

当进程在运行中需要访问某部分程序和数据时,发现其所在页面不在内存,就立即提出请求(向CPU发出缺中断),由系统将其所需页面调入内存。这种页面调入方式叫请求调页。

为实现请求调页,核心配置了四种数据结构:页表、页框号、访问位、修改位、有效位、保护位等。

二、页面置换算法

当CPU接收到缺页中断信号,中断处理程序先保存现场,分析中断原因,转入缺页中断处理程序。该程序通过查找页表,得到该页所在外存的物理块号。如果此时内存未满,能容纳新页,则启动磁盘I/O将所缺之页调入内存,然后修改页表。如果内存已满,则须按某种置换算法从内存中选出一页准备换出,是否重新写盘由页表的修改位决定,然后将缺页调入,修改页表。利用修改后的页表,去形成所要访问数据的物理地址,再去访问内存数据。整个页面的调入过程对用户是透明的。

常用的页面置换算法有

1、最佳置换算法(Optimal)

2、先进先出法(Fisrt In First Out)

3、最近最久未使用(Least Recently Used) 4、最不经常使用法(Least Frequently Used) 5、最近未使用法(No Used Recently) 三、参考程序:

#define TRUE 1 #define FALSE 0 #define INVALID -1 #define NULL 0

#define total_instruction 320 /*指令流长*/ #define total_vp 32 /*虚页长*/ #define clear_period 50 /*清0周期*/

typedef struct /*页面结构*/ { int pn,pfn,counter,time; }pl_type;

pl_type pl[total_vp]; /*页面结构数组*/

struct pfc_struct{ /*页面控制结构*/ int pn,pfn; struct pfc_struct *next; };

typedef struct pfc_struct pfc_type;

pfc_type pfc[total_vp],*freepf_head,*busypf_head,*busypf_tail;

int diseffect, a[total_instruction];

int page[total_instruction], offset[total_instruction];

-30-

《操作系统原理》实验指导书

???? 五、分析

1、从几种算法的命中率看,OPT最高,其次为NUR相对较高,而FIFO与LRU相差无几,最低的是LFU。但每个页面执行结果会有所不同。

2、OPT算法在执行过程中可能会发生错误 [思考问题]

1、为什么OPT在执行时会有错误产生? [实验报告要求]

1.调试说明。包括:调试情况,如上机时遇到问题及解决办法,观察到的现象及其分析,对程序设计技巧的总结及分析等;程序的输出结果及对结果的分析;实验的心得体会,以及调试日期等需要记录的信息。

2.程序框图。

3.经教师签名的程序清单。

4.程序中使用的数据结构及符号说明。 5.程序运行时的初值和运行结果。

-36-

《操作系统原理》实验指导书

实验七 文件管理

[实验目的]

通过一个简单多用户文件系统的设计,加深理解文件系统的内部功能及内部实现 [实验学时] 4学时

[实验类型] 综合性

[实验内容]

为LINUX 设计一个简单的二级文件系统。要求做到以下几点: 1、可以实现下列几条命令(至少4条) Login

用户登录

Dir 列文件目录

创建文件 Create

删除文件 Delete

Open 打开文件 Close 关闭文件 Read 读文件 Write 写文件

2、列目录时要列出文件名、物理地址、保护码和文件长度 3、源文件可以进行读写保护

实验准备

1、首先应确定文件系统的数据结构:主目录、子目录及活动文件等。主目录和子目录都

以文件的形式存放于磁盘,这样便于查找和修改;

2、用户创建的文件,可以编号存储于磁盘上。如file0,file1,file2??并以编号作为物理地址,在目录中进行登记。

[实验步骤] 一、文件管理

要将文件存储在磁盘(带)上,必须为之分配相应的存储空间,这就涉及到对文件存储空间的管理;采取何种方式存储,又涉及到文件的物理结构;为了简化对文件的访问和共享,还应设置相应的用户文件描述表及文件表。

1、文件存储空间的管理 (1)文件卷的组织

UNIX中,把每个磁盘(带)看作是一个文件卷,每个文件卷上可存放一个具有独立目录结构的文件系统。一个文件卷包含许多物理块,并按块号排列如下图:

0# 1# 2# 3# ??K# K+1# ??N#

其中,0#块用于系统引导或空闲,1#为超级块(superblock),存放文件卷的资源管理信息,如整个文件卷的盘块数、磁盘索引结点的盘块数、空闲盘块号栈及指针等。2#~K#存放磁盘索引结点。每个索引结点64B,第K+1#~N#存放文件数据。 (2)空闲盘块的组织

UNIX采用成组链接法组织空闲盘块。它将若干个空闲盘块划归一个组,将每组中所有

-37-

《操作系统原理》实验指导书

盘块号存放在其前一组的第一个空闲盘块中,而第一组中所有空闲盘块号放入超级块的空闲盘块号栈中。

例: 超级块表

109 106 103 100 95

211 208 205 202

310 307 304 301

(3)空闲盘块的分配与回收

内核要从文件系统中分配一盘块时,先检查超级块空闲盘块号栈是否已上锁。是则调用sleep睡眠,否则将超级块中空闲盘块栈栈顶盘块号分配出去。

回收时,若空闲盘块号栈未满,直接将回收盘块编号记入空闲盘块号栈中。若回收时栈已满,须先将栈中的所有空闲盘块号复制到新回收的盘块中,再将新回收盘块的编号作为新栈的栈底块号进栈。

2、文件的物理结构

UNIX未采用传统的三种文件结构形式,而是将文件所占用盘块的盘块号,直接或间接地存放在该文件索引结点的地址项中。查找文件时,只需找到该文件的索引结点,便可直接或间接的寻址方式获得指定文件的盘块。

过程bmap可将逻辑文件的字节偏移量转换为文件的物理块号。先将字节偏移量转换为文件逻辑块号及块内偏移量,再把逻辑块号转换为文件的物理块号。

3、用户文件描述符表和文件表的管理

每个进程的U区中设置一张用户文件描述符表。只在首次打开文件时才需给出路径名。内核在该进程的用户文件描述符表中,分配一空项,取其在该表中的位移量作为文件描述符fd(file discriptor)返还给用户。当用户再次访问该文件时,只需提供fd,系统根据fd便可找到相应文件的内存索引结点。fd表项的分配由ufalloc完成。

为了方便用户对文件进行读/写及共享,系统中设置了一张文件表。每个用户在打开文件时,都要在文件表中获得一表项,其中包含下述内容:

f.flag:文件标志,指示该文件打开是为了读或写; f.inode:指向打开文件的内存索引结点指针; f.offset:文件读写指针偏移值; f.count:文件引用计数。 二、目录管理

UNIX中,为了加速对文件目录的查找,将文件名和文件说明分开,由文件说明形成一个称为索引结点的数据结构,而相应的文件目录项则只由文件符号名和指向索引结点的指针构成。

对目录的管理应包括的功能有: 1、对索引结点的管理

每个文件都有一唯一的磁盘索引结点(di_node)。文件被打开后,还有一个内存索引结点(i_node)。创建一新文件时,就为之建立一个磁盘索引结点,以将文件的有关信息记入其中,并将用户提供的文件名和磁盘索引结点号一并组成一个新目录项,记入其父目录文件中。文件被撤消时,系统要回收该文件的磁盘索引结点,从其父目录中删除该目录项。随着文件的打开与关闭,系统还要为之分配和回收内存索引结点。 (1)磁盘索引结点

磁盘索引结点中,包含有关文件的下述一系列信息:

-38-

《操作系统原理》实验指导书

文件模式di_mode。可以是正规文件、目录文件、字符特别文件、块特别文件和管道文件等几种;

文件所有者用户标识符di_uid。指拥有该文件的用户标识符;

同组用户标识符di_gid。与拥有该文件的用户在同一小组的用户标识符; 文件长度di_size。以字节计数的文件大小;

文件的联接计数di_nlink。表明在本文件系统中所有指向该文件的文件名计数;

文件的物理地址di_addr。di_addr地址项共有13项,即di_addr(0) 到di_addr(12),每个地址项占3字节;

文件的访问时间di_atime。指文件最近被进程访问的时间;

文件的修改时间di_mtime。指文件和索引结点最近被进程修改的时间; 文件的建立时间di_citime。 (2)内存索引结点

文件被打开后,系统为它在内存索引结点表区中建一内存索引结点,以方便用户和系统对文件的访问。其中,一部分信息是直接从磁盘索引结点拷贝过来的,如i_mode、i_uid、i_gid、i_size、i_addr、i_nlink等,并又增加了如下各信息:

索引结点编号i_number。作为内存索引结点的标识符;

状态i_flag。指示内存索引结点是否已上锁、是否有进程等待此i结点解锁、i结点是否被修改、是否有最近被访问等标志;

引用计数i_count。记录当前有几个进程正在访问此i结点,每当有进程访问此i结点时,对i_count+1,退出-1;

设备号i_dev。文件所属文S件系统的逻辑设备号; 前向指针i_forw。Hash队列的前向指针; 后向指针i_back。Hash队列的后向指针; (3)磁盘索引结点的分配与回收

分配过程ialloc:当内核创建一新文件时,要为之分配一空闲磁盘i结点。如分配成功,便再分配一内存i结点。其过程如下:

检查超级块上锁否。由于超级块是临界资源,诸进程必须互斥地访问它,故在进入ialloc后,要先检查它是否已上锁,若是则睡眠等待;

检查i结点栈空否。若i结点栈中已无空闲结点编号,则应从盘中再调入一批i结点号进栈。若盘中已无空闲i结点,则出错处理,返回;

从空闲i结点编号栈中分配一i结点,并对它初始化、填写有关文件的属性; 分配内存i结点;

将磁盘i结点总数-1,置超级块修改标志,返回。 回收过程ifree:

当删除文件时,应回收其所占用的盘块及相应的磁盘i结点。具体有:

检查超级块上锁否。若是,直接返回,即不把本次回收的i结点号记入空闲i结点编号栈中;

检查i结点编号栈满否。若已满,无法再装入新回收的i结点号,立即返回,若未满,便将回收的i结点编号进栈,并使当前空闲结点数+1; 置超级块修改标志,返回。

(4)内存索引结点的分配与回收 分配过程iget:

虽然iget用在打开文件时为之分配i结点,但由于允许文件被共享,因此,如果一文件已被其他用户打开并有了内存i结点,则此时只需将i结点中的引用计数+1。如果文件尚未被任何用户(进程)打开,则由iget过程为该文件分配一内存i结点,并调用bread过程将其磁盘i结点的内容拷贝到内存i结点中并进行初始化。

-39-

《操作系统原理》实验指导书

回收过程iput:

进程要关闭某文件时,须调用iput过程,先对该文件内存i结点中的引用计数-1。若结果为0,便回收该内存i结点,再对该文件的磁盘i结点中的连接计数减1,若其结果也为0,便删除此文件,并回收分配给该文件的盘块和磁盘i结点。 2、构造目录make_node

文件系统的一个基本功能是实现按名存取,它通过文件目录来实现。为此须使每一个文件都在文件目录中有一个目录项,通过查找文件目录可找到该文件的目录项和它的索引结点,进而找到文件的物理位置。对于可供多个用户共享的文件,则可能有多个目录项。如果要将文件删除,其目录项也应删除。

构造目录先调用ialloc为新建文件分配一磁盘i结点及内存i结点。若分配失败则返回,分配成功时须先设置内存i结点的初值(含拷贝),调用写目录过程wdir,将用户提供的文件名与分配给该文件的磁盘i结点号一起,构成一新目录项,再将它记入其父目录文件中。 3、检索目录namei

用户在第一次访问某文件时,需要使用文件的路径名,系统按路径名去检索文件目录,得到该文件的磁盘索引结点,且返回给用户一个fd。以后用户便可利用该fd来访问文件,这时系统不需再去检索文件目录。

namei根据用户给出的路径名,从高层到低层顺序地查找各级目录,寻找指定文件的索引结点号。检索时,对以'/'开头的路径名,须从根目录开始检索,否则,从当前目录开始,并把与之对应的i结点作为工作索引结点,然后用文件路径名中的第一分量名与根或与当前目录文件中的各目录项的文件名,逐一进行比较。由于一个目录文件可能占用多个盘块,在检索完一个盘块中所有目录项而未找到匹配的文件分量名时,须调用bmap和bread过程,将下一个盘块中的所有目录项读出后,再逐一检索。若检索完该目录文件的所有盘块而仍未找到,才认为无此文件分量名。

检索方式采用Hash方法。 三、主要文件操作的处理过程 1、打开文件open

检索目录。内核调用namei从根目录或从当前目录,沿目录树查找指定的索引结点。若未找到或该文件不允许存取,则出错处理返回NULL,否则转入下一步;

分配内存索引结点。如果该文件已被其它用户打开,只需对上一步中所找到的i结点引用计数+1,否则应为被打开文件分配一内存i结点,并调用磁盘读过程将磁盘i结点的内容拷贝到内存i结点中,并设置i.count=1; 分配文件表项。为已打开的文件分配一文件表项,使表项中的f.inode 指向内存索引结点; 分配用户文件描述表项。 2、创建文件creat

核心调用namei,从根目录或当前目录开始,逐级向下查找指定的索引结点。此时有以下二种情况:

重写文件。namei找到了指定i结点,调用free释放原有文件的磁盘块。此时内核忽略用户指定的许可权方式和所有者,而保持原有文件的存取权限方式和文件主。最后打开。 新建。namei未找到。调用ialloc,为新创建的文件分配一磁盘索引结点,并将新文件名及所分配到的i结点编号,写入其父目录中,建立一新目录项。利用与open相同的方式,把新文件打开。

3、关闭文件close

根据用户文件描述符fd,从相应的用户文件描述符表项中,获得指向文件表项的指针fp,再对该文件表项中的f.count-1。 四、主要数据结构

1、i节点

-40-

本文来源:https://www.bwwdw.com/article/oh1d.html

Top