《操作系统》基本课程实验指导书-2014

更新时间:2024-03-09 07:49:02 阅读量: 综合文库 文档下载

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

北 京 邮 电 大 学

计算机学院

《操作系统》课程实验

Linux 操作系统内核 实 验 指 导 书

2014年9月

目 录

1.实验大纲 .................................................................................................................... 5

1.1 实验目的 ............................................................................................................ 5 1.2实验内容说明 ...................................................................................................... 5

1.2.1 第1组 系统安装实验................................................................................ 5 1.2.2 第2组Linux内核实验 .............................................................................. 6 1.2.3 第3组 进程管理....................................................................................... 6 1.2.4 第4组 存储管理....................................................................................... 7 1.2.5 第5组 进程通信....................................................................................... 7 1.2.6 第6组 I/O设备管理 ................................................................................. 8 1.2.7 第7组 文件系统管理................................................................................ 8

!1.3实验要求 ............................................................................................................ 9 2. 系统安装实验 ............................................................................................................ 10

2.1 实验1.1 Linux系统安装 .................................................................................... 10

1、实验目的 .................................................................................................... 10 2、实验内容(以Red Hat Linux7.2为例) ........................................................ 10 2.2 实验1.2 虚拟机VM软件安装............................................................................11

1、实验目的 .....................................................................................................11 2、实验内容 .....................................................................................................11 2.3 实验1.3 Shell编程 ............................................................................................ 12

1、实验目的与内容 .......................................................................................... 12 2、程序源代码清单(参考) ............................................................................ 12 3. Linux内核实验 ........................................................................................................... 13

3.1 实验2.1 观察Linux行为................................................................................. 13

1、实验目的 .................................................................................................... 13 2、实验内容 .................................................................................................... 13 3、程序源代码清单(参考) ............................................................................ 13 3.2 实验2.2 内核定时器 ....................................................................................... 15

1、实验目的 .................................................................................................... 15

2、实验内容 .................................................................................................... 16 3、程序源代码清单(参考) ............................................................................ 16 3.3 实验2.3内核模块 ............................................................................................. 23

1、实验目的 .................................................................................................... 23

2、实验内容 .................................................................................................... 23 3、实验原理 .................................................................................................... 23 4、实验步骤 .................................................................................................... 23 3.4 实验2.4 系统调用 ............................................................................................ 26

1、实验目的 .................................................................................................... 26 2、实验内容与步骤 .......................................................................................... 26

4 进程管理实验 ............................................................................................................. 28

4.1 实验3.1 进程行为观察 ..................................................................................... 28

1、实验目的 .................................................................................................... 28 2、实验内容 .................................................................................................... 28 4.2 实验3.2 代码分析 ............................................................................................ 28

1、实验目的 .................................................................................................... 28 2、实验内容 .................................................................................................... 28 4.3 实验3.3 Shell编程 ............................................................................................ 28

1、实验目的 .................................................................................................... 28

2、实验内容1.................................................................................................. 28 3、实验内容2.................................................................................................. 30

5. 存储管理实验 ............................................................................................................ 33

5.1 实验4.1 观察实验 ............................................................................................ 33

1、实验目的 .................................................................................................... 33 2、实验内容 .................................................................................................... 33 5.2 实验4.2 存储管理代码分析 .............................................................................. 33

1、实验目的 .................................................................................................... 33 2、实验内容 .................................................................................................... 33 3、示例—缺页中断处理程序分析 ..................................................................... 33 5.3 实验4.3虚拟存储器管理 ................................................................................... 35

1、实验目的 .................................................................................................... 35

2、实验内容 .................................................................................................... 35 3、实验原理 .................................................................................................... 36

4、试验步骤 .................................................................................................... 36 5、源程序代码清单(参考) ............................................................................ 37

6. 进程通信 ................................................................................................................... 39

6.1 实验5.1 观察实验 ............................................................................................ 39

1、实验目的与内容 .......................................................................................... 39 2、实验原理 .................................................................................................... 39 6.2 实验5.2 代码分析 ............................................................................................ 39

1、实验目的 .................................................................................................... 39 2、实验内容 .................................................................................................... 40 3、实验结果示例 ............................................................................................. 40 6.3 实验5.3 进程同步实验 ..................................................................................... 42

1、实验目的 .................................................................................................... 42 2、实验内容 .................................................................................................... 42 3、实验原理 .................................................................................................... 42 4、实验步骤及部分代码清单(参考) .............................................................. 43

7 I/O设备管理实验 ...................................................................................................... 46

7.1 实验6.1. 观察实验............................................................................................ 46

1、实验目的 .................................................................................................... 46

2、实验内容 .................................................................................................... 46 3、实验结果示例 ............................................................................................. 46 7.2 实验6.2 代码分析 ............................................................................................ 47 7.3 实验6.3 编程实验 ............................................................................................ 47

1、实验目的 .................................................................................................... 47

2、实验原理 .................................................................................................... 47 3、程序源代码清单(参考) ............................................................................ 47 7.4 实验6.4 设备驱动程序 ..................................................................................... 48

1、实验目的 .................................................................................................... 48 2、实验内容 .................................................................................................... 48 8. 文件系统管理实验 ..................................................................................................... 49

8.1 实验7.1 代码分析 ............................................................................................ 49

1、实验目的 .................................................................................................... 49 2、实验内容 .................................................................................................... 49 3、分析报告示例 ............................................................................................. 49 8.2 实验7.2 编程实验1 .......................................................................................... 51

1、实验目的与内容 .......................................................................................... 51 2、程序源代码清单(参考) ............................................................................ 51 8.3 实验7.3 编程实验2 .......................................................................................... 52

1、实验目的与内容 .......................................................................................... 52 2、程序源代码清单(参考) ............................................................................ 53

1.实验大纲

1.1 实验目的

在学习《操作系统》课程内容同时,以开放式源代码操作系统Linux为实验平台,同步完成Linux操作系统内核的代码分析和修改等7组基本课程实验。通过实验,熟悉Linux系统使用方法,掌握Linux内核系统结构,了解Linux进程管理、存储管理、设备管理、文件系统等资源管理功能的实现机理和典型算法。初步掌握运用内核开发环境对内核进行修改完善的能力。

通过本课程实验,使得学生熟悉Linux操作系统相关技术,并进一步巩固

课堂所学有关操作系统人机界面和资源管理得相关知识;并通过Linux源代码分析和简单编程,培养学生对实际操作系统的基本系统分析能力。

1.2实验内容说明

Linux基本实验由以下7组实验组成。

1.2.1 第1组 系统安装实验

实验1.1 Linux系统安装

从CD-ROM安装Red Hat Linux操作系统,如Red Hat Linux7.2,建立后续各个实验的运行环境。 实验1.2 虚拟机安装

在配备Windows操作系统Host机上,安装虚拟机软件Virtual PC for

Windows或VMware For Windows,进行BIOS设定, 对硬盘进行分区和格式化,安装Linux操作系统,以便在一台机器上模拟出多种操作系统运行环境。 实验1.3 Shell编程

编制简单的Shell程序,该程序在用户登录时自动执行,显示某些提示信息,

如“Welcome to Linux”, 并在命令提示符中包含当前时间、当前目录和当前用户名等基本信息。

1.2.2 第2组Linux内核实验

实验2.1 观察Linux行为

学习linux内核、进程、存储和其他资源的一些重要特性。通过使用/proc

文件系统接口, 编写一个程序检查反映机器平衡负载、进程资源利用率方面的各种内核值, 学会使用/proc文件系统这种内核状态检查机制。 实验2.2 内核定时器

学习掌握内核定时器的实现原理和方法,建立一种用户空间机制来测量多

线程程序的执行时间。 实验2.3 内核模块

模块是Linux系统的的一种特有机制,可用于动态扩展操作系统内核功能。

编写实现某些特定功能的模块,将其作为内核的一部分在管态下运行。例如, 通过内核模块编程在/porc文件系统中实现系统时钟的读操作接口。 实验2.4 系统调用

向现有Linux内核加入一个新的系统调用从而在内核空间中实现对用户空

间的读写。例如,设计并实现一个新的内核函数mycall( ),此函数通过一个引用参数的调用返回当前系统时间,功能上基本与gettimeofday( )相同。

1.2.3 第3组 进程管理

实验3.1 进程行为观察

1. 在Linux下,分别用snice、skill、top 等命令和/proc中的有关目录、文件观察系统中进程运行情况和CPU工作情况。

2. 在Linux下,用ptrace()、gdb跟踪一个进程的运行情况,用strace工具跟踪 fork() 过程,用ltrace工具跟踪 execl() 过程。观察并分析跟踪信息。 实验3.2 代码分析

阅读分析Linux中的进程建立模块、进程撤销模块、进程调度模块、系统

调用总入口模块,了解进程的创建、执行、等待、退出等过程。

实验3.3 Shell编程

1. 以超级用户身份编程,计算某一时段中所有程序平均运行时间。

2. 通过编写shell程序,了解子进程的创建和父进程与子进程间的协同,获得

多进程程序的编程经验。

1.2.4 第4组 存储管理

实验4.1 观察实验

1. 在Linux下,使用gdb程序观察一个程序文件的内容和结构。启动该程序

执行,再用GDB观察其内存映象的内容和结构。 2. 在Linux下,用free 和vmstat命令观察内存使用情况。

3. 在Linux下,查看/proc与内存管理相关的文件,并解释显示结果。 4. 在Linux下,用malloc()函数实现cat或copy命令。 实验4.2 代码分析

阅读 Linux/Minix中以下模块的调用主线,并写出分析报告 ? exec系统调用的内部实现模块调用主线 ? malloc函数的内部实现模块调用主线 ? 缺页中断处理程序 实验4.3 虚拟存储器管理

学习Linux虚拟存储实现机制;编写代码,测试虚拟存储系统的缺页错误

(缺页中断)发生频率。

1.2.5 第5组 进程通信

实验5.1 观察实验

在Linux下,用ipcs()命令观察进程通信情况。 实验5.2 代码分析

阅读 Linux/Minix中以下模块的调用主线,并写出分析报告。(1)kill系

统调用内部实现模块调用主线。(2)pipe系统调用内部实现模块调用主线。 实验5.3 进程同步实验

在学习linux内核的同步机制基础上,深入分析各种同步机制的实现方案,设计和编写一套同步原语。

1.2.6 第6组 I/O设备管理

实验6.1. 观察实验

1.stat命令查看机器上硬盘特别文件的I节点内容。

2.在Linux下,查看/proc与内存管理相关的文件,解释显示结果。 实验6.2 代码分析

阅读 Linux/Minix中以下模块的调用主线(1)print函数内部实现模块调用主线。(2) scan函数内部实现模块调用主线。写出分析报告。 实验6.3 编程实验

编写一个daemon进程,该进程定时执行 ps命令,然后将该命令的输出写至文件F1尾部。 实验6.4 设备驱动程序

了解Linux的设备驱动程序的组织结构和设备管理机制,编写简单的字符设备和块设备驱动程序。

1.2.7 第7组 文件系统管理

实验7.1 代码分析

阅读 Linux/Minix中有关文件模块的调用主线,并写出分析报告,包括 ? 文件建立模块,即系统调用create() ? 文件删除模块,即系统调用rm() ? 读/写模块,即 read/write 实验7.2 编程实验1

在Linux环境下,编写 Shell程序,计算磁盘上所有目录下平均文件个数、所有目录平均深度、所有文件名平均长度 实验7.3编程实验2

在Linux环境下,编写一个利用Linux系统调用删除文件的程序,加深对文件系统和文件操作的理解。

!1.3实验要求

? 学生以小组为单位,每组人数不超过2人。

? 以上7组实验中,每组至少完成1个实验,完成的实验总数不少

于8个,其中编程实验不少于4。

? “实验1.2虚拟机VM软件安装”“实验2.3内核模块”、“实验2.4

系统调用”、为必做实验。

? 实验完成后提交课程实验报告文档,并验收程序代码和上机演示。 ? 课程实验报告要求

对于编程实验,报告应包括:题目,实验目的、实验内容、实验设计原理、实验步骤、实验结果及分析和人员任务分配等。

2. 系统安装实验

2.1 实验1.1 Linux系统安装

1、实验目的

从CD-ROM安装Red Hat Linux操作系统,如Red Hat Linux7.2,建立后续各个实验的运行环境。

2、实验内容(以Red Hat Linux7.2为例)

Red Hat Linux7.2 安装光盘共有两张,第一张可直接从光盘启动,包含大部分的软件包和一些安装工具。第二张光盘包含许多附加软件包。以下为安装过程和注意事项。 (1)启动安装程序。用Linux的第一张光盘,从光驱引导启动程序,进入启动界面,显示提示符 ”boot: ”,选择图形模式进行安装。 (2)选择安装界面的使用语言 (3)选择默认的键盘设置

(4)选择默认的鼠标设置

(5)选择安装类型。Red Hat Linux提供了个人桌面、工作站、服务器和定制等多种安装类型。本实验选择个人桌面或定制方式。

(6)进行硬盘分区。Red Hat Linux采用了“装载”的处理方式,将1个分区和1个目录联系起来,每个分区都是整个文件系统的一部分。

Linux最少需要2个分区:Linux native(文件)分区、Linux Swap(交换)分区。前者用于存放Linux系统文件,只能用EXT2分区类型,在分区时应将载入点设置为“/”目录; 后者用作交换空间,将主存内暂时不用的数据缓存起来。建议采用如下分区方案

? SWAP分区

SWAP分区大小至少等于实际系统内存容量,一般可取为内存的2倍。 ? /boot分区

包含操作系统内核和启动时所用文件。建立单独的/boot分区后,即使主要根分区出了问题,系统仍然能够启动。此分区大小约在50MB-100MB之间

? /分区

根目录挂载位置。系统运行所需要的其它文件都在该分区,大小约在1.7GB 到5GB之间

初次安装系统时,最好选择自动安装方式。如果安装者对系统比较熟悉,可以用系统配置的营盘管理工具Disk Druid来订制所需分区。

(7)将文件系统设置为EXT2

(8)配置引导装载程序。选择LILO作为引导安装程序。LILO可以安装在第一硬盘的主引导区(MBR)或Linux分区的引导扇区。如果使用LILO来做双启动,须选择前者;如果用Linux启动软盘或其它系统引导器引导Linux,选择后者,即将LILO安装在Linux 分区的引导扇区。

(9)网络和防火墙配置

(10)选择默认的语言及其他语言支持 (11)时区配置

(12)设置root配置 (13)选择软件包组 (14) 筹建引导盘 (15) 配置显卡 (16) 进行安装

2.2 实验1.2 虚拟机VM软件安装

1、实验目的

在配备Windows操作系统Host机上,安装虚拟机软件Virtual PC for Windows或VMware For Windows, 进行BIOS设定, 对硬盘进行分区和格式化,安装Linux操作系统,以便在一台机器上模拟出多种操作系统运行环境。

通过本实验,进一步掌握课堂上所讲的虚拟机的概念。

2、实验内容

实验前的准备:

1、 获取安装介质 2、 熟悉虚拟机的操作

安装步骤(以Vmware为例):

1、 虚拟机软件的安装及设置 (1)、安装VMware,输入虚拟机序列号 (2)、创建一个新的虚拟机。

第一步:“File”->“New Virtual Machine”->“Custom”->“Next”->操作系统那栏选

Linux->“Next”。

第二步:设置虚拟机名以及配置文件 ->“Next”。 第三步:设置虚拟机的内存大小。

第四步:网络连接,使用默认设置->“Next”。

第五步:磁盘设定,如果你不是想让红旗Linux桌面4.0终生运行在虚拟机里,请选 “Use a physical disk”,让虚拟机与当前系统共用同一硬盘,而不是虚拟出一个硬盘。有一定风险,但是只要不胡乱操作,风险不大->“Next”。

第六步:指定要使用的硬盘->“Next”,设置配置文件的位置->“Finish”,忽略那个风险提示。

(3)、光驱软驱默认情况下也是和当前系统共用的,使用iso文件引导虚拟机,则“Edit virtual machine settings”,在左侧列表中选“DVD/CD-ROM”那项,再在右侧选“Use ISO image:”,指定安装红旗Linux桌面4.1的iso文件。

(4)、虚拟机默认不是从光盘引导的,要在它的BIOS里改,得先“Start this virtual machine”。如果出现“Do not forget to ...”的提示框,直接点“OK”。待VMware窗口中一大块变黑的时候,赶快用鼠标点那块黑,那块黑是虚拟机的屏幕。现在你的鼠标和键盘就转为控制虚拟机了。注意虚拟机屏幕下方的进度条,在走完之前,按“F2”键进行BIOSs设定。

(5)、用键盘的左右箭头键选中“Boot”标签,用上下箭头键选中“CD-ROM”。同时用“Shift”键和“+”键,把“CD-ROM”拎到顶上。用键盘的左右箭头键选中“Exit”标签,用上下箭头键选中“Exit Saving Changes”,回车->“YES”,等待虚拟机重新启动。同时按“Ctrl”和“Alt”键,鼠标和键盘就从虚拟机中解脱出来了。看到进度条的时候按VMware窗口左上方的红方块,停掉虚拟机。

2.3 实验1.3 Shell编程

1、实验目的与内容

通过本实验,了解Linux系统的shell机制,掌握简单的shell编程技巧。

编制简单的Shell程序,该程序在用户登录时自动执行,显示某些提示信息,如“Welcome to Linux”, 并在命令提示符中包含当前时间、当前目录和当前用户名等基本信息。

2、程序源代码清单(参考)

#include #include int main(){

printf(\int pid; int state; int pfd[2]; pipe(pfd);

if (fork()==0){ printf(\

dup2(pfd[0],0); close(pfd[0]); close(pfd[1]);

execlp(\perror(\

}

esle if(fork()==0){

printf(\ dup2(pfd[1],1); }

close(pfd[1]); close(pfd[0]); wait(&state);

close(pfd[0]);

close(pfd[1]);

execlp(\perror(\

}

wait(&state);

3. Linux内核实验

3.1 实验2.1 观察Linux行为

1、实验目的

学习linux内核、进程、存储和其他资源的一些重要特性。通过使用/proc文件系统接口, 编写一个程序检查反映机器平衡负载、进程资源利用率方面的各种内核值, 学会使用/proc文件系统这种内核状态检查机制。

2、实验内容

编写一个默认版本的程序通过检查内核状态报告Linux内核行为。程序应该在stdout上打印以下值:

1,CPU类型和型号;

2,所使用的Linux内核版本;

3,从系统最后一次启动以来已经经历了多长时间(天,小时和分钟); 4,总共有多少CPU时间执行在用户态,系统态,空闲态; 5,配置内存数量;当前可用内存数,磁盘读写请求数; 6,内核上下文转换数;

7,系统启动到目前创建了多少进程。

设计思路:

首先得到命令行,再解释命令行,然后到/proc查找文件,最后执行命令。

3、程序源代码清单(参考)

#include #include

int main( int argc, char *argv[]) {

char repTypeName[16]; char c1, c2, ch; int interval, duration; char *lineBuf; int LB_SIZE; FILE *thisProcFile; char *now;

int iteration;

//决定报告类型

strcpy(repTypeName, \ if (argc < 1) {

sscanf(argv[1],\ if (c1 != '-') {

fprintf(stderr, \ exit(1); }

if (c2 == 's') {

strcpy(repTypeName, \ }

if (c2 == \ {

strcpy(repTypeName, \ interval = atoi(argv[2]); duration = atoi(argv[3]); } }

//得到当前时间

/* gettimeofday(&now, NULL); */

printf(\ thisProcFile = fopen(\ //打开文件 fgets(lineBuf, LB_SIZE + 1, thisProcFile); //读取文件 printf(\ //打印文件 fclose(thisProcFile);

//关闭文件

//内核版本

thisProcFile = fopen(\ fgets(lineBuf,LB_SIZE + 1,thisProcFile); printf(\ersion: %s\\n\ fclose(thisProcFile);

//CPU类型和型号

thisProcFile = fopen(\ fgets(lineBuf,LB_SIZE + 1,thisProcFile); printf(\ fclose(thisProcFile);

//当前时间

thisProcFile = fopen(\fgets(lineBuf,LB_SIZE + 1,thisProcFile); printf(\fclose(thisProcFile);

//内存情况

printf(\

thisProcFile = fopen(\ while (! feof(thisProcFile)) { putchar(fgetc(thisProcFile)); }

fclose(thisProcFile);

// 当前状态

printf(\

thisProcFile = fopen(\ while (! feof(thisProcFile)) { putchar(fgetc(thisProcFile)); }

fclose(thisProcFile);

iteration = 0; interval = 2; duration = 60;

while(iteration < duration) {

sleep(interval);

thisProcFile = fopen(\ while (! feof(thisProcFile)) { putchar(fgetc(thisProcFile)); }

fclose(thisProcFile); iteration += interval; } return(0); }

3.2 实验2.2 内核定时器

1、实验目的

学习掌握内核定时器的实现原理和方法,建立一种用户空间机制来测量多线程程序的执

行时间。

2、实验内容

A、 用定时器ITIMER_REAL实现gettimeofday的功能。使其一秒钟产生一个信号,

计算已经过的秒数。 设计思路:

设置定时器ITIMER_REAL间隔为一秒钟。并为计时到时设定信号处理程序,即singal(SIGALRM,?),使其输出当前所记时间。

3、程序源代码清单(参考)

A.3、shell程序源代码清单

/****part1.c*****/ //part 1

#include #include #include

static void sighandle(int); static int second = 0; int main(){ }

struct itimerval v;

signal(SIGALRM,sighandle); v.it_interval.tv_sec = 1; v.it_interval.tv_usec = 0; v.it_value.tv_sec = 1;

v.it_value.tv_usec = 0;

setitimer(ITIMER_REAL,&v,NULL); for(;;);

static void sighandle(int s) {second++; }

printf(\fflush(stdout);

B、记录一个进程运行时所占用的real time, cpu time,user time ,kernel time。

设计思路:

任务开始前设置好定时器ITIMER_REAL,ITIMER_VIRTUAL,ITIMER_PROF,即

其相应的信号处理程序。在任务执行过程中内核定时器通过产生等间隔的信号来记录进程所需的各种时间参量,并在任务结束后打印出来。

B.3、shell程序源代码清单

/************part2.c**********/

//part2

#include #include #include

static void sighandle(int); static long realsecond = 0; static long vtsecond = 0;

static long profsecond = 0;

static struct itimerval realt,virtt,proft; int main(){

struct itimerval v; int i,j;

long moresec,moremsec,t1,t2; signal(SIGALRM,sighandle); signal(SIGVTALRM,sighandle); signal(SIGPROF,sighandle); v.it_interval.tv_sec = 10; v.it_interval.tv_usec = 0; v.it_value.tv_sec = 10; v.it_value.tv_usec = 0;

setitimer(ITIMER_REAL,&v,NULL); setitimer(ITIMER_VIRTUAL,&v,NULL);

setitimer(ITIMER_PROF,&v,NULL); for(j= 0;j<1000;j++){

for(i= 0;i<500;i++){printf(\ } getitimer(ITIMER_PROF,&proft);

getitimer(ITIMER_REAL,&realt); getitimer(ITIMER_VIRTUAL,&virtt); printf(\

moresec = 10 - realt.it_value.tv_sec;

moremsec = (1000000 - realt.it_value.tv_usec)/1000;

printf(\

moresec = 10 - proft.it_value.tv_sec;

moremsec = (1000000 - proft.it_value.tv_usec)/1000;

printf(\

moresec = 10 - virtt.it_value.tv_sec;

moremsec = (1000000 - virtt.it_value.tv_usec)/1000;

printf(\

t1 = (10 - proft.it_value.tv_sec)*1000 + (1000000 - proft.it_value.tv_usec)/1000 + profsecond*10000; t2 = (10 - virtt.it_value.tv_sec)*1000 + (1000000 - virtt.it_value.tv_usec)/1000 + vtsecond*10000; }

static void sighandle(int s) { }

switch(s){ case SIGALRM:realsecond+=10;break; case SIGVTALRM:vtsecond+=10;break; case SIGPROF:profsecond+=10;break;

default :break; }

moresec = (t1 - t2)/1000; moremsec = (t1 - t2) % 1000;

printf(\fflush(stdout);

C、编写一个主程序产生两个子进程,分别低轨计算N =20,30,36的Fibonacci序列。分

别对三个进程计算相应的real time, cpu time,user time ,kernel time。 设计思路:

与(2)原理基本相同,不同的只是在任务开始前要分别设定好每个进程的定时器,而且其最终的实验结果也由相应进程自身打印出来。

C.3、shell程序源代码清单

/**************part3.c***************/ //part3

#include #include #include

#include

static void c1_sighandle(int s); static void c2_sighandle(int s); static void p_sighandle(int s);

static long p_realt_secs = 0,c1_realt_secs = 0,c2_realt_secs = 0; static long p_virtt_secs = 0,c1_virtt_secs = 0,c2_virtt_secs = 0; static long p_proft_secs = 0,c1_proft_secs = 0,c2_proft_secs = 0; static struct itimerval p_realt,c1_realt,c2_realt; static struct itimerval p_virtt,c1_virtt,c2_virtt; static struct itimerval p_proft,c1_proft,c2_proft; static struct itimerval ini_value;

int main(){ int fib = 0; int pid1,pid2; int status;

long moresec,moremsec,t1,t2; pid1 = fork();

if (pid1 == 0){//c1 //set c1 signal handle c);

moresec = 10 - c1_virtt.it_value.tv_sec;

moremsec = (1000000 - c1_virtt.it_value.tv_usec)/1000;

printf(\

moresec = 10 - c1_proft.it_value.tv_sec;

moremsec = (1000000 - c1_proft.it_value.tv_usec)/1000;

printf(\

signal(SIGALRM,c1_sighandle); signal(SIGVTALRM,c1_sighandle); signal(SIGPROF,c1_sighandle); ini_value.it_interval.tv_sec = 10; ini_value.it_interval.tv_usec = 0; ini_value.it_value.tv_sec = 10; ini_value.it_value.tv_usec = 0; //set c1 timer

setitimer(ITIMER_REAL,&ini_value,NULL); setitimer(ITIMER_VIRTUAL,&ini_value,NULL); setitimer(ITIMER_PROF,&ini_value,NULL); fib = fibonacci(20);

//get timer of c1 and print

getitimer(ITIMER_REAL,&c1_realt); getitimer(ITIMER_VIRTUAL,&c1_virtt); getitimer(ITIMER_PROF,&c1_proft); printf(\

moresec = 10 - c1_realt.it_value.tv_sec;

moremsec = (1000000 - c1_realt.it_value.tv_usec)/1000;

printf(\

t1=(10-c1_proft.it_value.tv_sec)*1000+(1000000-c1_proft.it_value.tv_usec)/1000 +

c1_proft_secs*10000; t2=(10-c1_virtt.it_value.tv_sec)*1000+(1000000-c1_virtt.it_value.tv_usec)/1000 + c1_virtt_secs*10000; moresec = (t1 - t2)/1000;

moremsec = (t1 - t2) % 1000;

printf(\fflush(stdout); exit(0);

}//end c1

else{

pid2 = fork();

if (pid2 == 0){//c2 //set c2 signal handle

signal(SIGALRM,c2_sighandle); signal(SIGVTALRM,c2_sighandle); signal(SIGPROF,c2_sighandle); ini_value.it_interval.tv_sec = 10; ini_value.it_interval.tv_usec = 0; ini_value.it_value.tv_sec =10; ini_value.it_value.tv_usec = 0;

//set c2 timer

setitimer(ITIMER_REAL,&ini_value,NULL); setitimer(ITIMER_VIRTUAL,&ini_value,NULL); setitimer(ITIMER_PROF,&ini_value,NULL); fib = fibonacci(30);

//get timer of c2 and print

getitimer(ITIMER_PROF,&c2_proft); getitimer(ITIMER_REAL,&c2_realt); getitimer(ITIMER_VIRTUAL,&c2_virtt); printf(\

moresec = 10 - c2_realt.it_value.tv_sec;

moremsec = (1000000 - c2_realt.it_value.tv_usec)/1000;

printf(\emsec);

moresec = 10 - c2_proft.it_value.tv_sec;

moremsec = (1000000 - c2_proft.it_value.tv_usec)/1000;

printf(\moresec = 10 - c2_virtt.it_value.tv_sec;

3.4 实验2.4 系统调用

1、实验目的

向现有Linux内核加入一个新的系统调用从而在内核空间中实现对用户空间的读写。 例如,设计并实现一个新的内核函数mycall( ),此函数通过一个引用参数的调用返回当前系统时间,功能上基本与gettimeofday( )相同。

也可以实现具有其它功能的系统调用。

2、实验内容与步骤

1. 添加新调用的源代码

在/usr/src/linux-2.4.7-10/kernel/sys.c中添加相应的调用代码

asmlinkage int sys_mycall(struct timeval *tv) { struct timeval ktv;

MOD_INC_USE_COUNT;

do_gettimeofday(&ktv);

if (copy_to_user(tv,&ktv,sizeof(ktv))){ MOD_DEC_USE_COUNT; return -EFAULT; }

MOD_DEC_USE_COUNT;

return 0; }

2. 连接系统调用

a、修改/usr/src/linux-2.4.7-10/include/asm-i386/unistd.h,

在系统调用列表后面相应位置添加一行

#define _NR_mycall 222

新增加的调用号位222

b、修改/usr/src/linux-2.4.7-10/arch/i386/kernel/entry.S 在sys_call_table[]清单最后添加一行 .long SYMBOL_NAME(sys_mycall)

3. 重建新的Linux内核

cd /usr/src/linux-2.4.7-10/ make mrproper

make oldconfig made dep make clean make bzImage make modules

make modules_install

make install

4. 重建引导信息

a、在/boot/grub/grub.conf中自己添加一条新的启动选项,并使该选项指向

vimlinuz-2.4.7-10custom b、重新安装grub

5. 重新引导从新的内核进入

6. 修改/usr/lib/bcc/include/unistd.h,在系统调用列表后面相应位置添加一行

#define _NR_mycall 222

7.编写程序测试test.c:

#include #include

_syscall1(int,mycall,struct timeval *,thetime) main() { }

struct timeval gettime; struct timeval mycalltime; gettimeofday(&gettime,NULL); mycall(&mycalltime);

printf(\printf(\

4 进程管理实验

4.1 实验3.1 进程行为观察

1、实验目的

通过本实验了解并掌握Linux主要的进程管理命令。

2、实验内容

1. 在Linux下,分别用snice、skill、top 等命令和/proc中的有关目录、文件观察系统中进程运行情况和CPU工作情况。 2. 在Linux下,用ptrace()、gdb跟踪一个进程的运行情况,用strace工具跟踪 fork() 过

程,用ltrace工具跟踪 execl() 过程。观察并分析跟踪信息。

4.2 实验3.2 代码分析

1、实验目的

通过本实验了解Linux内核代码结构,掌握代码分析能力和技巧。

2、实验内容

实验内容为:选取 Linux内核中的进程建立模块、进程撤销模块、进程调度模块、系统调用总入口模块,阅读分析源代码,了解进程的创建、执行、等待、退出等过程。写出代码分析报告。

4.3 实验3.3 Shell编程

1、实验目的

通过编写shell程序,了解子进程的创建和父进程与子进程间的协同,获得多进程程序的编程经验。

2、实验内容1

设计一个简单的shell解释程序,能实现基本的bsh功能。

(1)设计思想:

将每一条命令分子段压入argv栈。然后再子进程中调用execvp()来实现该命令的功能。

shell程序源代码清单: (2)源代码清单

源代码xsh.c: #include #include #include

#define BUFFERSIZE 256

//最简单的shell,只是简单的执行命令调用,没有任何的其他功能 int main()

{

char buf[BUFFERSIZE],*cmd,*argv[100]; char inchar;

int n,sv,buflength; buflength = 0; for(;;) {

printf(\

//处理过长的命令; inchar = getchar();

while (inchar != '\\n' && buflength < BUFFERSIZE ){ buf[buflength++] = inchar; inchar = getchar(); }

if (buflength > BUFFERSIZE){

printf(\ buflength = 0; continue; }

else

buf[buflength] = '\\0';

//解析命令行,分成一个个的标记 cmd=strtok(buf,\ if(cmd) {

if(strcmp(cmd,\ n=0;

argv[n++]=cmd;

while(argv[n++]=strtok(NULL,\ if(fork()==0) {

execvp(cmd,argv);

fprintf(stderr,\ exit(1);

} wait(&sv); buflength = 0; } } }

(3)测试结果:

[root@localhost Work]# make xsh.c make: Nothing to be done for `xsh.c'. [root@localhost Work]# make xsh make: `xsh' is up to date. [root@localhost Work]# ./xsh => ps

PID TTY TIME CMD 29297 pts/2 00:00:00 bash 29344 pts/2 00:00:00 xsh 29345 pts/2 00:00:00 ps => ps | more

ps: error: Garbage option. usage: ps -[Unix98 options] ps [BSD-style options]

ps --[GNU-style long options] ps --help for a command summary => ps > ps.txt

ps: error: Garbage option. usage: ps -[Unix98 options] ps [BSD-style options]

ps --[GNU-style long options] ps --help for a command summary => ls

fibno_timer.c ksamp.c psTimeInfo.c shell1.c shell2.c timer.c xshbk xsh.c xshrb.c

ksamp ls.txt shell1 shell1.c~ shell3.c xsh xshbk.c xshrb => chsh

Changing shell for root. New shell [/bin/bash]:

3、实验内容2

编写一个带有重定向和管道功能的Shell

(1)设计思路

通过fork()创建子进程,用execvp()更改子进程代码,用wait()等待子进程结束。

这三个系统调用可以很好地创建多进程。另一方面,编写的Shell要实现管道功能,需要用pipe(创建管道使子进程进行通信。 说明:

? 本程序允许同时有重定向和管道,也可以不带它们,但是管道数目不得超过一个

? 重定向的位置应该是在最后

? 设有一个内部命令exit用来退出Shell (2)源代码清单(参考)

#include #include #include #include main() {

int hd;

char buf[256];

char *buf2,*buf3,*cmd,*cmd2,*cmd3,*argv[64],*argv2[64],*argv3[64]; int n,sv,fd[2]; for(;;) {

printf(\

if(fgets(buf,sizeof(buf),stdin)==NULL) exit(0); buf2=strstr(buf,\ buf3=strstr(buf, \ if (buf2)

*buf2++='\\0'; if(buf3)

*buf3++='\\0';

cmd=strtok(buf,\ if (cmd) {

if (strcmp(cmd,\ n=0;

argv[n++]=cmd;

while(argv[n++]=strtok(NULL,\ else exit(1); if (buf2){

cmd2=strtok(buf2,\ n=0;

argv2[n++]=cmd2;

while(argv2[n++]=strtok(NULL,\ if (buf3){

cmd3=strtok(buf3,\ n=0;

argv3[n++]=cmd3;

while(argv3[n++]=strtok(NULL,\

if (!cmd2){

if (fork() == 0) { execvp(cmd,argv);

fprintf(stderr,\ %s\\n\ exit(1);} wait(&sv); } else {

} } }

pipe(fd); if(fork()==0) { hd=-1;

dup2(fd[0],0);

if (cmd3) hd=open(cmd3, O_CREAT|O_WRONLY,0666); if (hd != -1 ) dup2(hd,1); close(fd[0]); close(fd[1]); close(hd);

execvp(cmd2,argv2);

fprintf(stderr,\ ******ERROR******: %s\\n\ } else if(fork()==0) { dup2(fd[1],1); close(fd[0]); close(fd[1]);

execvp(cmd,argv);

fprintf(stderr,\ ******ERROR******: %s\\n\ }

close(fd[0]); close(fd[1]); wait(&sv); wait(&sv);

5. 存储管理实验

5.1 实验4.1 观察实验

1、实验目的

利用Linux相关程序和命令,观察程序结构和进程执行情况。

2、实验内容

1. 在Linux下,使用gdb程序观察一个程序文件的内容和结构。启动该程序执行,再用GDB观察其内存映象的内容和结构。

2. 在Linux下,用free 和vmstat命令观察内存使用情况。

3. 在Linux下,查看/proc与内存管理相关的文件,并解释显示结果。

5.2 实验4.2 存储管理代码分析

1、实验目的

了解Linux内核中存储管理部分的代码结构和主要功能。

2、实验内容

阅读 Linux/Minix中以下模块的调用主线,并写出分析报告

? exec系统调用的内部实现模块调用主线 ? malloc函数的内部实现模块调用主线 ? 缺页中断处理程序

3、示例—缺页中断处理程序分析

当程序在运行中,访问到的无效的虚拟地址的时候,系统将激发出缺页中断。激发缺页中断的情况通常有四种:

1. C-O-W型中断,当某个进程进行写操作时,如果写的页是多进程在使用时,为了不影响其它进程的正常运行,通常需要将该页复制一份,供执行写操作的进程单独使用。

2. 被访问的物理页由于太长时间没有访问而被kswapd置换到swap file中。 3. 被访问的物理页由于是第一次访问,所以还在磁盘上或由于访问后被置换时

因为没有发生写操作,而未写到swap file中。

4. 当进程动态的访问一片存储区域时,如在程序中动态开辟的数组等,则该页

不在swap file中,也不在磁盘上。

缺页中断服务入口程序是函数do_page_fault。do_page_fault首先进行各种错误情况判断,并作相应处理。然后根据error_code 来判断缺页中断类型: (1) 第一种情况采用do_wp_page函数来处理

(2) 第二、三、四种情况由do_no_page函数来处理。

下面将分别介绍这些函数的流程图。

void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, int write_access)

为复制可写页申请一页空间异常根据address计算pgd ,pmd,pte退出=1使用该物理页的进程>1 ?>1将物理页复制到复制页上将该物理页置\将复制页链入虚存中释放原先分配的复制页将指向原先物理页的pte释放掉退出

图1 do_wp_page示意图

void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, int write_access) {

根据address计算三级页表中pgd/pmd/pte的值,如无对应的项,分配空间将

其填上

if ( pte_present(entry) )

该页已在内存中,return;

//可能是共享该页的其他进程已将该页读入

else if (!pte_none(entry)) //情况2 pte中该项非空,说明该页被kswapd置换到swap file中,

调用 do_swap_page读入该页;

else if ( !vma->vm_ops || !vma->vm_ops->nopage) //情况4 该页对应的VMA块没有相应的nopage操作,说明该VMA块对应的是数据段内容

}

调用__get_free_page操作为该页分配内存,并将该页赋值为0,同时链入

该进程的页表中

else //情况3 调用虚拟块操作将磁盘中对应文件读入page中,

将pte表中对应的项指向该页。

将该页dirty位置位,如果该页有多进程使用,且非共享,置写保护位。

根据address计算三级页表中pgd/pmd/pte的值,如无对应的项,分配空间将其填上在空(2)该页在内存中?不在该页非空?不在(4)退出调用vma->vm->ops->swapin在(3)该页有无no_page操作调用__get_free_page重新分配内存,将该page赋值为0,同时链入tsk的页表中调用虚拟块操作将磁盘中对应的文件读入page中将page置”dirty”,如果该页有多进程使用,且非共享,置写保护位退出将page的entry链入tsk的页表图 2 do_no_page示意图( 2、3、4分别代表2、3、4种情况)

参考文献:《莱昂氏源代码分析》

5.3 实验4.3虚拟存储器管理

1、实验目的

学习Linux虚拟存储实现机制;编写代码,测试虚拟存储系统的缺页错误(缺页中断)发生频率。

2、实验内容

修改存储管理软件以便可以判断特定进程或者整个系统产生的缺页情况,达到一下目标 ? 预置缺页频率参数 ? 报告当前缺页频率

#include #include int main () { pid_t pid;

int pfd[2];

char send_buf[100], recv_buf[100]; pipe (pfd); pid = fork (); if (pid == 0) { } else {

pid = fork (); if (pid == 0) { close (pfd[0]); } else {

read (pfd[0], recv_buf, sizeof(recv_buf)); printf (\

read (pfd[0], recv_buf, sizeof(recv_buf)); printf (\wait (0); wait (0); close (pfd[0]);

strncpy (send_buf, \lockf (pfd[1], F_LOCK, 0);

write (pfd[1], send_buf, strlen(send_buf)); sleep (1);

lockf (pfd[1], F_ULOCK, 0); close (pfd[1]); close (pfd[0]);

strncpy (send_buf, \lockf (pfd[1], F_LOCK, 0);

write (pfd[1], send_buf, strlen(send_buf)); sleep (1);

lockf (pfd[1], F_ULOCK, 0); close (pfd[1]);

} }

return 0;

}

pipe的调用主线:

pipe (pfd);pid = fork (); 如果pid == 0,则调用:

close (pfd[0]);strncpy ();lockf ();write ();sleep ();lockf ();函数,通过进程向管道中写入数据, 如果调用不成功,调用了close (pfd[0]);strncpy ();lockf ();write ();sleep ();lockf ();函数,创建一个进程,如果成功,通过该进程向管道中写入数据;如果不成功,则从管道中读出数据。

6.3 实验5.3 进程同步实验

1、实验目的

深入学习Linux内核,在学习linux内核的同步机制的同时,深入分析各种同步机制的实现方案,在此基础上设计和编写一套同步原语。

2、实验内容

设计并实现一个新的同步原语,该原语允许多个进程因一个事件而阻塞,直到其他进程产生这个信号为止。当一个进程产生一个事件的信号时,所有因这个事件而阻塞的进程都取消阻塞。如果信号产生时,没有进程因为这个信号而阻塞,那么这个信号无效。

实现下列系统调用:

int evntopen(int); int evntclose(int);

int evntwait(int evenNum); void evntsig(int evenNum);

3、实验原理

在深入学习软中断信号,信号量和管道的工作原理和实现机制后,我们知道,一个事件必须有一个事件号,一系列的进程等待这个事件发生,那么肯定需要一个等待队列,所以睡眠的进程就放到这个队列中去。通过考察linux中如wake_up、sleep_on等的实现我们将构建上述同步原语。

首先建立一个存放事件的队列,通过简单的链表即可实现。 //定义结构,保存事件队列 typedef struct __eventStruct{ int eventNum;

wait_queue_head_t *p;

struct __eventStruct *next; } __eventNode;

//两个全局变量记录链表的头尾

__eventNode *lpmyevent_head = NULL; //指向链表头 __eventNode *lpmyevent_end = NULL; //指向链表尾

4、实验步骤及部分代码清单(参考)

(1)实现函数定义

定义Open同步原语,当Open一个事件的时候,有两种情况:一是事件已经存在,只需要返回Event事件号即可,第二种是事件链表中没有该事件,简单的处理办法直

接返回-1,表示事件不存在。当传递参数0 的时候,将产生一个新事件。 int eventopen(int eventNum) {

__eventNode *newNode; __eventNode *prevNode; if(eventNum)

if(!scheventNum,&prev)) return -1; else return eventNum; else {

newNode = (__eventNode *)kmalloc(

sizeof(__eventNode), GFP_KERNEL); newNode->p =(wait_queue_head_t *)kmalloc(

sizeof(wait_queue_head_t));

newNode->next = NULL;

newNode->p->task_list.next = &newNode->p->task_list; newNode->p->task_list_prev =

&newNode->p->task_list;

if(!lpmyevent_head)

{

newNode->eventNum =2;

lpmyevent_head =lpmyevent_end =newNode; return newNode->eventNum; } else {

newNode->eventNum = lpmyevent_end->eventNum + 2; lpmyevent_end->next = newNode; lpmyevent_end = newNode; }

return newNode->eventNum; } return 0;

}

定义evntsig(eventNum),evntsig()要完成的功能是唤醒所有等待该事件发生的进程。我们只需要在事件列表上找到该事件,然后调用wake_up()。

int evntsig(int eventNum) {

__eventNode *tmp = NULL; __eventNode *prev = NULL;

if(!(tmp = scheventNum(eventNum,&prev)) return;

wake_up(tmp->p); return 1; }

evntwait()将一个进程加到他要等待的事件队列中去。

int evntwait(int eventNum) {

__eventNode *tmp; __eventNode *prev = NULL; wait_queue_t wait;

unsigned long flags;

if(tmp =scheventNum(eventNum,&prev)) {

wait.task = current;

current->state = TASK_UNINTERRUPTIBLE; write_lock_irqsave(&temp->p->lock,flags); __add_wait_queue(tmp->p,&wait); write_unlock(&tmp->p-lock);

schedule();

write_lock_irq(&tmp->p->lock);

__remove_wait_queue(tmp->p,&wait); write_unlock_irqrestore(&tmp->p->lock,flags); }

}

至于evntclose()先在事件队列中找到该事件,然后根据事件在该链表中的位置进行特定的处理,之后唤醒所有睡眠在该事件上的事件,最后将这个事件从链表中删除,释放内存。

int evntclose(int eventNum) {

__eventNode *prev; __eventNode *releaseItem;

evntsig(eventNum);

if(releaseItem = scheventNum(eventNum,&prev)) {

if (releaseItem == lpmyevent_end)

lpmyevent_end = prev; if (releaseItem == lpmyevent_head) {

lpmyevent_head = lpmyevent_head->next; goto wake; }

prev->next = releadeItem->next; } wake:

if(releaseItem) {

kfree(releaseItem); return 1; } return 0;

} 最后是一个辅助调度函数scheventNum()函数。他有两个参数eventNum和prev,前者是事件号,后者是要返回的一个 __eventNode类型的指向指针的指针,它将指向要要寻找节点的上一节点。函数返回要寻找的事件节点。 __eventNode * scheventNum(int eventNum,__eventNode **prev) {

__eventNode *tmp = lpmyevent_head; *prev = NULL; while(tmp)

{

if(tmp->eventNum == eventNum) return tmp; *prev = tmp; tmp =tmp->next; }

return NULLL; }

(2)同步原语实现的函数转化为系统调用,修改系统初始化代码,编译内核。

7 I/O设备管理实验

7.1 实验6.1. 观察实验

1、实验目的

掌握与设备管理有关的Linux命令。

2、实验内容

? 用stat命令查看机器上硬盘特别文件的I节点内容

? 在Linux下,查看/proc与内存管理相关的文件,解释显示结果

3、实验结果示例

参见以下截图

7.2 实验6.2 代码分析

阅读 Linux/Minix中以下模块的调用主线(1)print函数内部实现模块调用主线。(2) scan函数内部实现模块调用主线。写出分析报告。

7.3 实验6.3 编程实验

1、实验目的

编写一个daemon进程,该进程定时执行 ps命令,然后将该命令的输出写至文件F1尾部。通过此实验,掌握Linux I/O系统相关内容。

2、实验原理

在这个程序中,首先fork一个子程序,然后,关闭父进程,这样,新生成的子进程被交给init进程接管,并在后台执行。

新生成的子进程里,使用system系统调用,将ps的输出重定向,输入到f1.txt里面。

3、程序源代码清单(参考)

main() { }

int p;

p = fork(); if(p > 0) {

exit(0); }

else if(p == 0) {

for(i = 0; i < 100; i++) { }

sleep(100);

system(\

} else { }

perror(\

7.4 实验6.4 设备驱动程序

1、实验目的

了解Linux的设备驱动程序的组织结构和设备管理机制,编写简单的字符设备和块设备驱动程序。

2、实验内容

a.

编写字符型设备驱动程序,该字符设备包括5个基操作:scull_open()、scull_write()、scull_read、scull_ioctl、scull_release(), 同时还需要编写一个测试程序 b.

编写字符型设备驱动程序,该字符设备包括5个基操作:sbull_open()、sbull_write()、sbull_read、sbull_ioctl、sbull_release()

8. 文件系统管理实验

8.1 实验7.1 代码分析

1、实验目的

了解与文件管理有关的Linux内核模块的代码结构。

2、实验内容

阅读 Linux/Minix中有关文件模块的调用主线,并写出分析报告,包括

? 文件建立模块,即系统调用create() ? 文件删除模块,即系统调用rm() ? 读/写模块,即 read/write

3、分析报告示例

A. 创建文件模块分析

5780 /*creat system call */ 5781 Creat() 5782 {

5783 resister *ip; 5784 extern uchar; 5785

5786 ip = namei(&uchar,1); 5787 if(ip == NULL){ 5788 if(u.u_error) 5789 return;

5790 ip = maknode(u.u_arg[1]&07777&(~ISVTX)); 5791 if (ip == NULL) 5792 return; 5793 open1(ip,FWRITE,2); 5794

}else

5795 open1(ip,FWRITE,1); 5796 }

第5 7 8 6:“namei”( 7 5 1 8 )将一路径名变换成一个“inode”指针。“uchar”是一个过程的名字,它从用户程序数据区一个字符一个字符地取得文件路径名。

5 7 8 7:一个空“inode”指针表示出了一个错,或者并没有具有给定路径名的文件存在。 5 7 8 8:对于出错的各种条件,请见U P M的C R E AT ( I I )。 5 7 9 0:“maknode”( 7 4 5 5 )调用“ialloc”创建一内存“ inode”,然后对其赋初值,并使其进入适当的目录。注意,显式地清除了“粘住”位( I S V T X )。

B. 删除文件rm模块分析

3510 unlink() 3511 {

3512 resister *ip,*pp; 3513 extern uchar; 3514

3515 pp = namei(&uchar,2); 3516 if (pp ==NULL) 3517 return; 3518 prele(pp);

3519 ip = iset(pp ->dev,u.u_dent.u_ino); 3520 if (ip == NULL)

3521 panic (*unlink – iset *);

3522 if ((ip ->i_mode%IFMT) == IFDIR && !suser()) 3523 goto out;

3524 u.u_offset[1] = - DIRSIZ+2; 3525 u.ubase = &u.u_dent; 3526 u.ucount = DIRSIZE +2; 3527 u.u_dent.u_ino = 0; 3528 writei(pp); 3529 ip ->i_nlink--; 3530 ip->i_flag =! IUPD; 3531

3532 out:

3533 iput(pp); 3534 iput(ip); 3535 }

新文件作为永久文件自动进入文件目录。关闭文件不会自动地造成文件被删除。当内存“ inode”项中的“ i _ nlink”字段值为0并且相应文件未被打开时,将删除该文件。在创建文件时,该字段由“ m a k n o d e”赋初值为1。系统调用“ link”( 5 9 4 1 )可将其值加1,系统调用“unlink”( 3 5 2 9 )则可将其值减1。创建临时“工作文件”的程序应当在其终止前执行“ unlink”系统调用将这些文件删除。 注意,“unlink”系统调用本身并没有删除文件。当引用计数( i _ count )被减为0时( 7 3 5 0、7 3 6 2 ),才删除该文件。

为了减少在程序或系统崩溃时遗留下来的临时文件所带来的问题,程序员应当遵守下列约定:

(1) 在打开临时文件后立即对其执行“ unlink”操作。

(2) 应在“tmp”目录下创建临时文件。在文件名中包括进程标识数就可构成一惟一文件名

参考文献:《莱昂氏源代码分析》

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

Top