NachOS实验报告(4个全)

更新时间:2024-06-23 15:43:01 阅读量: 综合文库 文档下载

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

四 川 大 学

操作系统课程设计报告

学 院:专 业:年 级:组 编 号:组 成 员:提交时间:

软 件 学 院 软件工程专业 08级

2010年6月24日

指导教师评阅意见: . . . . .

指导教师评阅成绩::

实验项目一

项目名称:开发Shell程序 试验背景知识

Shell

此处的shell是指命令行式的shell。

文字操作系统与外部最主要的接口就叫做shell。shell是操作系统最外面的一层。shell管理你与操作系统之间的交互:等待你输入,向操作系统解释你的输入,并且处理各种各样的操作系统的输出结果。

shell提供了你与操作系统之间通讯的方式。这种通讯可以以交互方式(从键盘输入,并且可以立即得到响应),或者以shell script(非交互)方式执行。shell script是放在文件中的一串shell和操作系统命令,它们可以被重复使用。本质上,shell script是命令行命令简单的组合到一个文件里面。

Shell基本上是一个命令解释器,类似于DOS下的command.com。它接收用户命令(如ls等),然后调用相应的应用程序。较为通用的shell有标准的Bourne shell (sh)和C shell (csh)。

交互式shell和非交互式shell

交互式模式就是shell等待你的输入,并且执行你提交的命令。这种模式被称作交互式是因为shell与用户进行交互。这种模式也是大多数用户非常熟悉的:登录、执行一些命令、签退。当你签退后,shell也终止了。

shell也可以运行在另外一种模式:非交互式模式。在这种模式下,shell不与你进行交互,而是读取存放在文件中的命令,并且执行它们。当它读到文件的结尾,shell也就终止了。

实验目的:

Shell是一个命令处理器(command processor)——是一个读入并解释你输入的命令的程序,它是介于使用者和操作系统之核心程序(kernel)间的一个接口。它是一个交互性命令解释器。shell 独立于操作系统,这种设计让用户可以灵活选择适合自己的shell。

shell 让你在命令行键入命令,经过shell 解释后传送给操作系统(内核)执行。 为 Nachos 实现一个 Shell (字符终端)界面,通过该界面,用户可以实现类似于 Linux Shell 的大部分功能,实现Shell命令的cd,clr,dir,environ,echo,help,pause,quit,shell的环境变量应包含shell=/myshell ,其中pathname是执行Shell程序的完整路径。

参与人员及分工:

实验环境:Redhat Linux 9.0

NachOS-4.1

>试验环境的搭建:Vmware的安装,linuxd的安装,sin sight的安装

Vmware的安装

Vmware是一个虚拟机软件,它可以在windows平台上虚拟出真实机器的硬件环境的,使得我们可以在不购买新机器的情况下就可以在一个机器上运行多个操作系统。

Vmware的安装和普通的windows应用程序安装没有太大的差别,是一个相当“傻瓜”的过程,只要按照提示,依次点击“下一步”就可顺利地完成vmware的安装了。

虚拟机的创建

i. 如果所示,在file中选择new——新虚拟机

ii. 然后选择定制创建虚拟机——选择操作系统类型(linux-

redhat linux)——虚拟机名称和虚拟机文件安放的路径—

—虚拟机器模拟内存——网络选择——选择I/O适配器——硬盘创建——设置虚拟机器硬盘名称

如果所示: 定制虚拟机器

操作系统类型以及虚拟机名称和虚拟机文件安放的路径

虚拟机器模拟内存

1 把nachos4.1下载到/usr/local目录 2 tar -zvxf nachos-4.1.tgz

3 进入解压后的目录,其中有code子目录,再进入其中的build.linux子目录 4 输入 make depend

5 输入 make 看看结束有没有错误,如果没有,那么就成功了。

编译好的nachos系统镜像就在build.linux目录下,运行时直接 . / nachos 就可以了。

如果要到其他目录下运行的话,还要export才行。nachos详细运行参数可以用 . / nachos -u 得到。 交叉编译工具的搭建。

把下载的交叉编译工具放到 / 目录下,即根目录下然后用tar -zvxf 命令解压即可。必须放到根目录下,因为压缩包里面包含了/usr/local的目录层次。

另外还需要编译测试程序转换工具,进入 nachos4.1/code/coff2noff 运行 . / configure make 即可。

然后在Rat Hat上编译出nachos,其系统结构如下图所示: Si35Setup.rar的安装

虽然在linux我们可以高效地完成所有开发所需的任务,但是对于刚刚开始接触unix/linux的同学,一下子用熟那么多的工具还是有些困难的。正是基于这一点我们的教学网站上也提供了在windows下用来阅读代码的工具Source Insight,借助于它我们可以加快代码阅读速度。

这个软件的安装是个很简单的过程只要运行setup一路next下去就可以了。 代码阅读时要先建工程,点击project-new project,然后按照要求回答源代码的位置,工程就会顺利的建成。代码阅读时如果需要一些功能比如想要查找某个符号的定义只要在选定的符号上点右键就会弹出菜单,选择相应的命令就可以了。 Nachos的介绍

Nachos的全称是“Not Another Completely Heuristic Operating System”,它是一个可修改和跟踪的操作系统教学软件。它给出了一个支持多线程和虚拟存储的操作系统骨架,可让学生在较短的时间内对操作系统中的基本原理和核心算法有一个全面和完整的了解。

Nachos的目录结构

以上操作系统可以发现在工作目录下生成一个名为nachos-3.4 的目录。该目录中含有: copyright 文件 Nachos 的版权信息 readme 文件 Nachos 的readme 信息

nachos.ps 文件 Nachos 的介绍文档(Postscript 格式) c++example 目录 有关C++介绍和实例

doc 目录 Nachos 各个部分介绍和原有的作业要求 code 目录 Nachos 各个部分的源代码

最主要的部分是Nachos 的源代码部分。它的目录结构是: Makefile Makefile.common Makefile.dep 文件 文件 文件

Nachos 的Makefile 文件。当Nachos 需要移植到其它系统时, 可以修改Makefile.dep 中的HOST 参数 machine 目录 Nachos 虚拟机模拟部分源代码 threads 目录 Nachos 线程管理部分源代码 filesys 目录 Nachos 文件系统管理部分源代码 userprog 目录 Nachos 用户程序部分源代码 network 目录 Nachos 网络管理部分源代码 vm 目录 Nachos 虚拟内存管理部分源代码 test 目录 一些测试用应用程序

bin 目录 包含有用户程序目标码变换的程序

三、各个部分的编译运行

Nachos的各个部分都可以独立编译运行,也可以同时编译各个部分。全部编译可以采用如下

命令:

~/nachos-3.4$ make

当需要单独编译线程管理部分时,先进入threads 目录,然后采用如下命令: ~/nachos-3.4/threads$ make depend ~/nachos-3.4/threads$ make nachos

实际上,各部分目录下都有一个Makefile 文件,内容大体相同,区别在于一些条件编译的

参数。比如在单独编译线程管理部分时,文件管理部分就被屏蔽了,这样读者读者就可以专

心于线程管理部分的调试。

四、应用程序的编译

由于Linux 指令集和R2/3000 指令集不同,用户编写的应用程序用Linux 系统中标准gcc 编

译后,不能直接在Nachos 虚拟机环境下运行。所以需要采用交叉编译技术。所谓交叉编译

技术是在一个操作系统下将源码编译成另一个操作系统的目标码,这里就是在Linux 下通过

gcc 交叉编译版本将用户程序的源码编译成R2/3000 指令集的目标码。

在Linux 中,没有缺省的交叉编译工具。读者可以到上海交通大学计算机系FTP 服务器上

下载,URL 为:

ftp://donkey.cs.sjtu.edu.cn/linux/cross-compiler.tgz

该文件的解开需要有超级用户的权利,将解开至/usr/local/目录下: /# gzip -dc cross-compiler.tgz | tar xf -

在编译用户程序时,用交叉编译器将源码编译成R2/3000 指令集的目标代码,再经过一个简

单的转换就可以在Nachos 虚拟机上运行。注意,在读者实现虚拟存储之前,有些应用程序

可能会因为使用过多的内存而不能运行。

实验内容:

本项目在实践的过程中需要注意以下要点:

Shell项目的要求

一、 设计一个简单的命令行shell,满足下面的属性并且可以在指定的UNIX

平台下执行。

1. 这个shell支持一下内部命令:

a) cd——把当前默认目录改变为。如果没有

参数,则显示当前目录。如果该目录不存在,会出现合适的错误信息。 b) cle——清屏。

c) dir——列出目录的内容。 d) environ——列出所有的环境变量。

e) echo——在屏幕上显示并且换行(多个空格和制

表符可能被缩减为一个空格)。

f) help——显示用户手册,并且使用more命令过滤。 g) pause——停止shell操作直到按下回车键。 h) quit——推出shell。

i) shell的环境变量应该包含shell=/myshell,其中

/myshell是可以执行的shell完整路径(及shell的可执行路径,而不是他在目录下的硬连接路线)。

2. 其他的命令行输入被解释为程序的调用,shell创建并执行折个程序,

并作为自己的子进程。程序的执行的环境变量包含在以下条目中: parent=/shell,其中/myshell已经在1.i)中描述过了。

3. Shell必须能够从文件中提取命令输入 例如shell使用以下命令行被调用:

programname arg1 arg2 outputfile

这个批处理文件应该包括一组命令集,当到达文件结尾时shell退出。很明显,如果shell被调用是没有使用参数,他会在屏幕上显示提示符请求用户输入。

4. Shell必须支持i/o重定向,stdin和stdout,或者其中之一 a) 例如命令行:

programname arg1 arg2 outputfile

使用arg1以及arg2执行程序programname,输入文件流被替换为inputfile,输出文件流被替换为outputfile. b) stdout重定向应该支持一下的内部命令: i. dir ii. environ iii. echo iv. help

以上内部命令已在1中有具体解释,本处比在叙述。

使用输出重定向时,如果重定向字符为>,则创建输出文件,如果存在则覆盖之;如果重定向字符为〉〉,也会创建输出文件,如果存在则添加到文件尾。

5. shell必须支持后台程序执行。如果在命令行后面添加&字符,在加载

完程序后需要立刻返回命令行的提示符。命令行提示符必须包含当前路径。

二、 写一个关于使用如何使用shell的简单的用户手册,用户手册应该包括足

够的细节以方便UNIX的初学者简单方便的使用这个shell程序。

例如:解释i/o重定向,程序环境以及后台程序执行。用户手册必须命名为readme,必须为一个可以并准文件编辑器可以打开的简单的文档。

例如这个描述类型和深度的例子,cah和tcsh的在线帮助(man csh,man tcsh)。这两个shell明显比我们所谓的shell具有更加强大功能。所以用用户手册不一定要非常庞大,也不应包括编译指示——即文件列表和源代码,这个用户手册应该面向操作用户,所以台应该是一个操作用手册而不是一个程序员手册。

三、 源代码必须有很详细得注释,并且要有很好的组织结构以方便非制作人员

的阅读,维护或者修改。结构和注释使程序跟更加易于阅读和理解,并且可以保证批改你的作业的人不用很费劲的去读你的源代码。

四、 在提交的源代码文件中,包括: a) 原文件 b) makefile c) readme

并且这些源代码应该能够编译完成完整的结果。

五、 makefile必须产生二进制未见myshell。

例如一个makefile例子:

#Joe Citizen,s1234567-Operating Systems Project 1 #CompLab1/01 tutor: Fred Bloggs

myshell:myshell.c utility,c myshell.h gcc-Wall myshell.c utility.c-o myshell

在执行命令符键入make就会产生myshell程序。上述makefile从第4行必须以制表符开始。

六、 根据上述第6点的实例中,提交的目录中应该包含以下文件:

i. makefile ii. myshell.c

iii. iv. v. utility.c myshell.h readme

项目说明:可以通过调用Linux下的/bin/sh来实现该项目shell,主要是实现几个nachos系统调用:SysWrite,SysRead,SysExec,SysJoin,SysStrncmp 然后就是在exception.cc中调用这些系统调用 在shell中它们的作用:

? SysWrite: 显示提示符与shell的版本信息 ? SysRead:读取n个字符到缓存buffer

? SysExec 与SysJoin:主要是用来执行命令,如dir 等 。如果该命令不存在则打印错误信息

? SysStrncmp:比较两个字符串的前n个字符, 主要用来判断用户是否输入了exit命令以退出shell

Nachos中修改的地方: 1. syscall.h

添加了代码:#define SC_Strncmp 43

int Strncmp(char *buffer,char*str,int size); 2. Ksyscall 添加的代码: #include #include #include #include #include #include #include #include #include #include #include #include #include

#define SHELL \

int SysWrite(char*buffer ,int size,OpenFileId id) {

return write(id,buffer,(size_t)size); }

int SysRead(char*buffer ,int size,OpenFileId id) {

return read(id, buffer, (size_t) size); }

SpaceId SysExec(char* exec_name) {

pid_t child; child = vfork(); if(child == 0) {

execl (SHELL, SHELL, \ _exit (EXIT_FAILURE); }

else if(child < 0) return EPERM;

return (SpaceId) child; }

int SysJoin(SpaceId id) {

return waitpid((pid_t) id, (int*) 0, 0); }

int SysStrncmp(char*buffer,char *str,int n) {

return strncmp(buffer,str,(size_t)n); }

3. exception.cc case SC_Write:

DEBUG(dbgSys,\from buffer to consoleOutput\5)<machine->ReadRegister(6)<<\

char wbuffer[60];//the buffer to store information from userprogram int size ;

size=(int)kernel->machine->ReadRegister(5); OpenFileId printOut;

printOut= (OpenFileId)kernel->machine->ReadRegister(6); int addressOne;

addressOne=(int)kernel->machine->ReadRegister(4); int i; i=0; do{

kernel->machine->ReadMem(addressOne++,1,(int*)&wbuffer[i++]); }while(i

n1=SysWrite((char*)wbuffer,size,printOut); kernel->machine->WriteRegister(2,n1); /* Modify return point */ {

/* set previous programm counter (debugging only)*/ kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));

/* set programm counter to next instruction (all Instructions are 4 byte wide)*/

kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);

/* set next programm counter for brach execution */ kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg)+4); } return;

ASSERTNOTREACHED(); break; case SC_Read:

DEBUG(dbgSys, \from buffer\<< kernel->machine->ReadRegister(4) << kernel->machine->ReadRegister(5)<< kernel->machine->ReadRegister(6) << \ int rsize ;

rsize=(int)kernel->machine->ReadRegister(5); OpenFileId enterIn;

enterIn = (OpenFileId)kernel->machine->ReadRegister(6); char addressTwo;

addressTwo = (char)kernel->machine->ReadRegister(4); int local ;

local= (int)kernel->machine->ReadRegister(4);; int n2 ;

n2= SysRead(&addressTwo,rsize,enterIn);

kernel->machine->WriteMem(local,1,(int)addressTwo); kernel->machine->WriteRegister(2,n2); /* Modify return point */

{ /* set previous programm counter (debugging only)*/ kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));

/* set programm counter to next instruction (all Instructions are 4 byte wide)*/

kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);

/* set next programm counter for brach execution */ kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg)+4);

}

return;

ASSERTNOTREACHED(); break;

case SC_Exec:

DEBUG(dbgSys,\a command\ char ebuffer[60]; int addressThree;

addressThree = kernel->machine->ReadRegister(4); int c; c = 0; do{

kernel->machine->ReadMem(addressThree++,1,(int*)&ebuffer[c++]); }while(c<60);

kernel->machine->WriteRegister(2,SysExec(ebuffer)); /* Modify return point */

{/* set previous programm counter (debugging only)*/ kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));

/* set programm counter to next instruction (all Instructions are 4 byte wide)*/

kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);

/* set next programm counter for brach execution */ kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg)+4); }

return;

ASSERTNOTREACHED(); break;

case SC_Join:

DEBUG(dbgSys,\

kernel->machine->WriteRegister(2,SysJoin((SpaceId)kernel->machine->ReadRegister(4)));

/* Modify return point */ {

/* set previous programm counter (debugging only)*/ kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));

/* set programm counter to next instruction (all Instructions are 4 byte wide)*/

kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);

/* set next programm counter for brach execution */ kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg)+4); }

Return;

ASSERTNOTREACHED(); break;

case SC_Strncmp:

DEBUG(dbgSys, \two string \<< kernel->machine->ReadRegister(4) <machine->ReadRegister(5) << kernel->machine->ReadRegister(6) << \ int addressFour;

addressFour = kernel->machine->ReadRegister(4); int addressFive;

addressFive = kernel->machine->ReadRegister(5); char str1buffer[60]; char str2buffer[60]; int d,e; d= 0; e=0; do{

kernel->machine->ReadMem(addressFour++,1,(int*)&str1buffer[d++]); }while(d<60); --addressFour;

do{ kernel->machine->ReadMem(addressFive++,1,(int*)&str2buffer[e++]); }while(e<60); --addressFive; int n3;

n=SysStrncmp(str1buffer,str2buffer,kernel->machine->ReadRegister(6)); kernel->machine->WriteRegister(2,n3); /* Modify return point */

{/* set previous programm counter (debugging only)*/ kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));

/* set programm counter to next instruction (all Instructions are 4 byte wide)*/

kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);

/* set next programm counter for brach execution */ kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg)+4); } return;

ASSERTNOTREACHED(); break;

4. shell.c

Write( \if(Strncmp(buffer,\ {

Halt(); } 5. start.s

.globl Strncmp .ent Strncmp

Strncmp: addiu $2,$0,SC_Strncmp syscall j $31 .end Strncmp .globl Exit .ent Exit 实验结果:

执行命令 ./nachos –x ../test/shell.noff

实验项目二

项目名称:Nachos的线程管理模块升级 实验目的:完善Nachos的线程管理机制 参与人员及分工:

实验背景知识:

线程基础知识:

线程基本概念:是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。 线程状态:就绪、阻塞和运行三种基本状态。

线程是程序中一个单一的顺序控制流程.在单个程序中同时运行多个线程完成不同的工作,称为多线程.

线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文.多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定. 线程的运行中需要使用计算机的内存资源和CPU 线程的周期

新建 就绪 运行 阻塞 死亡 线程调度与优先级

有线程进入了就绪状态,需要有线程调度程序来决定何时执行,根据优先级来调度. 线程组

每个线程都是一个线程组的一个成员,线程组把多个线程集成一个对象,通过线程组可以同时对其中的多个线程进行操作.在生成线程时必须将线程放在指定的线程组,也可以放在缺省的线程组中,缺省的就是生成该线程的线程所在的线程组.一旦一个线程加入了某个线程组,不能被移出这个组.

进程和线程的关系

在引入线程机制后,进程不再是单一的动态实体,而是由两部分组成:

? 各线程活动的环境,包括:统一的地址控件、全局变量、打开文件和计时器等。

? 若干个线程,它们是进程中的活动部分,也是处理机的调度单位,而进程不再是处理机 的最小调度单位。

一个进程中的所有线程在同一地址空间中活动,共享该地址空间中的全局变量,共享打开文

件和计时器等。它们总是相互协作,各自承担一个作业中的某个部分。与传统的进程相似, 线程具有状态的变化。通常,这些状态是:运行、阻塞、就绪或终止。 表3.1 与进程和线程有关的主要信息表

Nachos 广泛采用线程的概念,是多线程操作系统。线程是Nachos 处理机调度的单位,在 Nachos 中线程分成两类,一类是系统线程。所谓系统线程是只运行核心代码的线程,它运 行在核心态下,并且占用宿主机的资源,系统线程共享Nachos 操作系统本身的正文段和数 据段;一个系统线程完成一件独立的任务,比如在Nachos 网络部分,有一个独立的线程一 直监测有无发给自己的数据报。

Nachos 的另一类线程同Nachos 中的用户进程有关。Nachos 中用户进程由两部分组成,核心

代码部分和用户程序部分。用户进程的进程控制块是线程控制块基础上的扩充。每当系统接 收到生成用户进程的请求时,首先生成一个系统线程,进程控制块中有保存线程运行现场的 空间,保证线程切换时现场不会丢失。该线程的作用是给用户程序分配虚拟机内存空间,并 把用户程序的代码段和数据段装入用户地址空间,然后调用解释器解释执行用户程序;由于 Nachos 模拟的是一个单机环境,多个用户进程会竞争使用Nachos 唯一的处理机资源,所以 在Nachos 用户进程的进程控制块中增加有虚拟机运行现场空间以及进程的地址空间指针等 内容,保证用户进程在虚拟机上的正常运行。

在下图中可以看出,系统线程竞争使用宿主机的CPU 资源,而用户进程的用户程序部分 竞争使用的是虚拟机的CPU 和寄存器。所以用户进程在被切换下处理机时,需要保存其系 统线程部分的现场,同时还需要保存虚拟机部分的现场。

实验环境:Redhat Linux 9.0

NachOS-4.1

实验内容:

本项目在实践的过程中需要注意以下要点: Nachos中线程管理特点

Nachos中线程管理特点1 ------线程个数没有限制

? 一般的操作系统,进程的数目是有限的,但是Nachos 中线程数目是无限的(没有

限制)(当然,用户进程的数目应该也是有限的。当虚拟机内存以及虚拟内存都耗尽时,就不能产生新的用户线程)。因为线程的控制结构和系统线程的运行是占用宿主机的。能够开多少线程完全由宿主机条件限制,理论上是无限的。

Nachos中线程管理特点2 ------线程调度简单

? 启动了时钟中断的情况下,当时钟中断到来时。如果就绪线程队列中有就绪线程,

就必须进行线程切换。

没有启动时钟中断的情况下,Nachos 使用非抢占式调度。 ? 概念:

非抢占式调度:进程在运行过程中不会切换到其它进程运行,除非其主动放弃处理机或者运行结束

抢占式调度:为了确保没有一个进程单独运行的时间太长,几乎所有的计算机系统都内置了时钟,周期性地进行时钟中断,在每一次时钟中断时,由进程调度程序负

? 实现多级目录后,添加、删除目录项要根据具体的路径,因此对树的遍历要有

深刻的理解。

3. 为了实现文件长度无限,要采取混合索引分配方式,必须对此概念有所了解。

⑵ 磁盘类Disk模拟了一个异步的磁盘.

a) 什么是同步/异步:

i) 同步: 所谓同步,就是在发出一个功能调用时,在没有得到结果之

前,该调用就不返回。

ii) 异步: 异步的概念和同步相对。当一个异步过程调用发出后,调用

者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者

b) 磁盘异步读写:

i) CPU发出读写请求,不需要等待执行完成. ii) 磁盘接收请求后自行完成读写操作. iii) CPU可自行执行其他事务.

vi) 磁盘读/写操作执行完毕后,通过中断,回调或其他方式通知CPU.

⑶ NachOS如何通过同步的文件读写函数模拟异步磁盘的?

a) Disk类本身是个回调对象,通过中断回调模拟磁盘读写完成后发回CPU的消息. b) 它接受一个回调对象作为读写操作执行后的事件通知.

⑷ 同步磁盘SynchDisk:

a) 通过信号量对异步的磁盘读写进行同步

b) 继承自回调对象,当异步磁盘读写完毕后进行回调 c) 每次磁盘读写完成后,信号量执行V操作. d) 每次发出读写请求后,信号量在P操作上等待.

⑸ 磁盘扇区:

a) 原始的磁盘读写操作是以扇区为单位的. b) NachOS中: i. SectorSize = 128 ii. SectorsPerTrack = 32 iii. NumTracks = 32 iv. NumSectors = (SectorsPerTrack * NumTracks) = 1024

⑹ NachOS文件格式:filehdr.h

a) 类FileHeader定义了文件头的格式. b) FileHeader的尺寸正好为一个扇区大小

c) 成员变量dataSectors中记录了该文件内容所在的扇区.

d) FetchFrom和WriteBack分别是从指定扇区读取文件头和向指定扇区写入文件头. e) 当前文件格式所支持的文件尺寸为:

(SectorSize – 2*sizeof(int))/sizeof(int)* SectorSize = 3840

NachOS的文件格式:

⑺ 类OpenFile描述一个文件:

a) 构造函数:从一个扇区中读出文件头. b) 读写函数ReadAt和WriteAt i. 计算待读写的内容在文件头dataSectors中的位置; ii. 读写取相应扇区的内容;

⑻ 文件系统中的两个特殊文件

a) freeMapFile: i. 此文件是一个位表(bitmap),用于标识磁盘中哪些扇区已被使用. ii. 此文件的文件头始终位于0号扇区. b) directoryFile: i. 此文件用于记录文件系统中各个文件的目录结构. ii. 此文件的文件头始终位于1号扇区.

⑼ 空闲表文件freeMapFile:

a) 类bitmap,按位标记. i. 在文件系统某,一位代表一个扇区. ii. Mark 将某位设置为1(标记某扇区被使用) iii. Clear 将某位设置为0(标记某扇区没有被使用) iv. Test 判断某位是否被置1(判断某扇区是否被使用) v. FindAndSet 寻找下一个为0的位设置为1(寻找空闲扇区) vi. NumClear 返回当前为0的位(查看磁盘剩余空间) vii. 持久位表: PersistentBitmap viii. 在Bitmap的基础上增加了向文件读写功能. ix. FetchFrom和WriteBack:分别用于从一个文件读取位表和将位表写入一个文

件. x. 写入的文件就是freeMapFile.

b) 目录文件directoryFile:

i) 用于记录各个文件信息和目录层次关系. ii) 类Directory用于描述这个这个目录文件.

iii) FetchFrom和WriteBack用于读取和写入此文件

⑽ DirectoryEntry用于表示一个文件

a) inUse 该实体是否被使用 b) Sector 文件头所在的扇区 c) Name 文件名

⑾ 类Directory用于记录文件目录

a) 这个类就是directoryFile.

b) 它对DirectoryEntry的组织是简单的顺序表.

c) 没有树形结构,并且文件个数也有限制(tableSize)

⑿ 文件系统如何整合工作的FileSystem:

a) 格式化: i. 在使用文件系统前,需要进行格式化:./nachos –f ii. 类FileSystem构造函数中,打开format标志进行格式化. b) 创建文件 c) 打开文件

d) 删除文件: i. ./nachos –r filename

⒀ 格式化步骤:

a) 创建PersistentBitmap对象代表磁盘空闲表, Directory对象代表磁盘目录结构. b) 创建freeMapFile和directoryFile文件 i. 创建freeMapFile和directoryFile的文件头. ii. 将freeMapFile和directoryFile所使用的固定文件头所在扇区(0号和1号)

在freemap中标记为1.

iii. 通过文件头中的Allocate函数分配文件尺寸(修改freemap和文件头的

dataSectors).

iv. 向磁盘写入文件头.

c) 将PersistentBitmap 和Directory 的内容写入freeMapFile和directoryFile

中: i. 利用OpenFile对象打开freeMapFile和directoryFile. 将PersistentBitmap 和Directory 写入这两个文件.

⒁ 创建文件的步骤:

a) 打开目录结构

b) 查找是否存在此文件,如果存在返回false

c) 打开空闲表,查找一个空闲的扇区,如果磁盘没有空间则返回false d) 根据名字和文件头扇区向目录结构中添加此文件的记录 e) 创建文件头,并通过Allocate函数和freemap分配文件空间 f) 将文件头写入先前取得的文件头扇区 g) 更新磁盘中的目录文件和空闲表文件

⒂ 打开文件:

a) 打开目录文件(directory->FetchFrom)

b) 查找目录中是否存在此文件(directory->Find)

c) 如果查找到此文件的文件头扇区编号,则通过OpenFile对象打开(new

OpenFile(sector))

⒃ 删除文件

a) 打开目录文件(directory->FetchFrom)

b) 查找目录中是否存在此文件(directory->Find) c) 根据查找到的文件头扇区打开文件头 d) 打开空闲表

e) 通过Deallocate函数修改空闲表中所有保存文件内容的扇区

(fileHdr->Deallocate(freeMap))

f) 将文件头扇区从空闲表中清零(freeMap->Clear(sector)) g) 从目录结构中删除此文件记录(directory->Remove(name)) h) 更新磁盘中的目录文件和空闲表文件

⒄ 文件系统的多线程访问机制:

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

Top