桂林理工大学——《操作系统》实习报告,何天从

  • 格式:doc
  • 大小:1.24 MB
  • 文档页数:29

操作系统实习报告

课题设计 磁盘调度管理

姓 名 何天从

学 号 3110757101

班 级 网络11-1班

院 系 信息科学与工程学院

指导老师 刘汉英

起止日期 2013.12.9~2013.12.20

操作系统实习

目录:

一、源代码分析(fork.c分析) …………………………1

1 理论基础 ………………………………………………1

2 代码分析结果 …………………………………………2

3 遇到的问题(如何解决)及体会 ……………………6

二、演示系统开发(磁盘调度管理) ……………………7

1 设计目的 …………………………………………………7

2 设计内容 …………………………………………………7

3 开发环境 …………………………………………………7

4 分析设计 …………………………………………………7

4.1 实验原理 ……………………………………………7

4.2 数据结构 ……………………………………………8

4.3 实现步骤 ……………………………………………13

4.4 程序流程图 ……………………………………………13

5 运行示例及结果分析 …………………………………19

6 遇到的问题(如何解决)及体会 ……………………26

7 参考文献 ………………………………………………27

8 源程序清单 ……………………………………………27

操作系统实习

-1- 第一部分、源代码分析

一、理论基础

Linux 内核的整体结构

Linux 内核由5 个主要的子系统组成。这5 个子系统分别是:

1、进程调度(SCHED);

2、内存管理(MM)

3、虚拟文件系统(Virtual File System,VFS)

4、网络接口(NET);

5、进程间通信(IPC)。

进程调度控制着进程对CPU 的访问。当需要选择下一个进程运行时,由调度程序选择最值得运行的进程。可运行进程实际是仅等待CPU 资源的进程,如果某个进程在等待其它资源,则该进程是不可运行进程。Linux 使用了比较简单的基于优先级的进程调度算法选择新的进程。

内存管理允许多个进程安全地共享主内存区域。Linux 的内存管理支持虚拟内存,即在计算机中运行的程序,其代码、数据和堆栈的总量可以超过实际内存的大小,操作系统只将当前使用的程序块保留在内存中,其余的程序块则保留在磁盘上。必要时,操作系统负责在磁盘和内存之间交换程序块。 内存管理从逻辑上可以分为硬件无关的部分和硬件相关的部分。硬件无关的部分提供了进程的映射和虚拟内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。

虚拟文件系统隐藏了各种不同硬件的具体细节,为所有设备提供了统一的接口,虚拟文件系统还支持多达数十种不同的文件系统,这也是Linux 较有特色的部分。虚拟文件系统可分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2、fat 等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。

网络接口提供了对各种网络标准的存取和各种网络硬件的支持。网络接口可分为网络协议和网络驱动程序两部分。网络协议部分负责实现每一种可能的网络传输协议,网络设备驱动程序负责与硬件设备进行通信,每一种可能的硬件设备都有相应的设备驱动程序。

进程间通信支持进程间各种通信机。

操作系统实习

-2- 二、代码分析结果

2.1 do_fork()函数的参数

(1) unsigned long clone_flags

显然,这是一个标志参数,在函数中用于区分创建的性质如是否子进程与父进程共享文件系统信息等等。具体出现在几个复制函数如copy_file(clone_flags,p)、copy_fs(clone_flags,p)、copy_sighand(clone_flags,p)、copy_mm(clone_flags,p)以及copy_thread(nr,clone_flags,usp,p,regs)中。而其使用方法是和几个linux定义的32位宏变量相与,结果是零则表示没有该宏变量对应的性质。具体的使用将在分析上述几个函数时说明。

(2) unsigned long usp

看样子这是一个寄存器的值,它出现在copy_thread函数中,对copy_thread()分析中可以看出这个参数的大致用法,似乎与堆栈有关。

(3) struct pt_regs *regs

pt_regs数据结构的定义在Linux\Include\Asm-i386\Ptrace.h文件,其中包含一些寄存器的值和标志。源代码中对这个结构的解释是这样的:

/*this struct defines the way the regsiters are stored on the stack *during a

system call.*/

2.2 fork.c文件中的全局变量

(1) int nr_tasks=1;

这里只能作大致的猜测,nr_tasks 变量是用于记录新创建的子进程连同父进程的个数,而且是和task数组相关。这一点在do_fork()函数中可以看出,当do_fork()把子进程的PCB初始化完并链接到进程队列中之后,nr_tasks增1:

p->start_time=jiffies;

task[nr]=p;

SET_LINKS(p);

nr_tasks++;

而在fork调用失败要滚回的时候,nr_tasks减1。

(2) int nr_running=1;

非常奇怪,在fork.c文件中仅定义了这个变量,以后再未出现,估计是标志可运行的进程个数。

(3)unsigned long int total_forks=0;

/* Handle normal Linux uptimes.*/

与nr_tasks不同,total_forks只有在fork操作成功之后才增1,显 然它是用来记录fork操作的个数 的。

(4) int last_pid=0;

last_pid是在创建中装载新建子进程的pid值的,从get_pid()函数中被赋值返回,送到do_fork() 中。

在get_pid()中:

repeat:

if((++last_pid)&0xffff8000)

操作系统实习

-3- last_pid=1;

for_each_task(p){

if(p->pid==last_piod||

p->pgrp==last_pid||

p->session==last_pid)

}

return last_pid;

(5)task_struct *current

这个变量的定义在fork.c文件中没有找到,但从源代码的字里行间可以十分清楚地看出current 是指向调用fork的进程的PCB的,即所谓父进程的task_struct 的地址。

2.3do_fork()函数中定义的几个局部变量

(1) int nr;

这个变量被赋以find_empty_process()函数的返回值,并用来表示新创建的子进程在task数组中的下标。而在find_empty_process()函数中正常的返回源代码如下:

for(i=0;i

if( !task[i])

return i;

可见,这个下标是对应task数组中为空的一项。

(2) int error= —ENOMEM;

do_fork()的返回值是int 类型的,如果fork调用成功,则正常的返回应当是

新建的子进程的p->pid号,如果fork失败,则返回error。有两种失败可能,一是返回-EAGAIN,一是返回-ENOMEM。

(3) unsigned long new_stack;

这是用来标示新建子进程分给核心堆栈的内存空间的。相关源代码如下:

new_stack=alloc_kernel_stack();

这里new_stack是此内存空间的首地址,然后由子进程把持:

p->kernel_stack_page=new_stack;

但具体Linux 是怎样分配堆栈还没有生入分析。

(4) struct task_struct *p;

显然,p是指向新建子进程的task_struct结构变量的,值得一提的是do_fork() 中一开始就做了 *p=*current 的语句,说明Linux是主张子进程复制父进程的PCB,然后再作一些初始化的修改以显示子之不同于父的一些个性。

2.4文件的复制copy_files()

在解释copy_files()的流程之前,有必要先看一下相关的数据结构:

1.task_struct中与文件相关的数据项是files

struct files_struct *files;

它指向一个files_struct结构变量。

2.files_struct

它描述的是一个进程已经打开的文件:

struct files_struct {

int count;

操作系统实习

-4- fd_set close_on_exec;

fd_set open_fds;

struct file * fd[NR_OPEN];

};

可以看出,Linux中一个进程最多只能同时打开NR_OPEN个文件,而且前三项分别设为标准输入、标准输出和出错信息输出文件。

3.file结构变量

每个打开的文件及插口附加项(socket etcetera)都由file结构表示:

struct file {

mode_t f_mode;

loff_t f_pos;

unsigned short f_flags;

unsigned short f_count;

unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;

struct file *f_next, *f_prev;

int f_owner; /* pid or -pgrp where SIGIO should be sent */

struct inode * f_inode; struct file_operations * f_op;