实验三 进程的创建实验
- 格式:doc
- 大小:198.00 KB
- 文档页数:36
《操作系统课程设计》实验报告学号:姓名:苏州大学计算机科学与技术学院2014年9月操作系统课程设计实验报告目录目录 (1)一、实验环境 (2)二、实验报告总体要求 (2)实验一编译L INUX内核 (3)实验二观察L INUX行为 (7)实验三进程间通信 (14)操作系统课程设计实验报告一、实验环境Linux平台◆硬件平台:普通PC机硬件环境。
◆操作系统:Linux环境,例如,红旗Linux或Red Hat Linux;启动管理器使用GRUB。
◆编译环境:伴随着操作系统的默认gcc环境。
◆工作源码环境:一个调试的内核源码,版本不低于2.4.20。
二、实验报告总体要求在2013年11月25日前提交实验报告。
实验报告至少要求包含以下内容:1.引言:概述本次实验所讨论的问题,工作步骤,结果,以及发现的意义。
2.问题提出:叙述本篇报告要解决什么问题。
注意不可以抄写实验要求中的表述,要用自己的话重新组织我们这里所提出的问题。
3.解决方案:叙述如何解决自己上面提出的问题,可以用小标题 3.1,3.2…等分开。
这是实验报告的关键部分,请尽量展开来写。
注意,这部分是最终课程设计的基本分的部分。
这部分不完成,本课程设计不会及格。
4.实验结果:按照自己的解决方案,有哪些结果。
结果有异常吗?能解释一下这些结果吗?同别人的结果比较过吗?注意,这部分是实验报告出彩的地方。
本课程设计要得高分,应该在这部分下功夫。
5.结束语:小结并叙述本次课程设计的经验、教训、体会、难点、收获、为解决的问题、新的疑惑等。
6.附录:加了注释的程序清单,注释行数目至少同源程序行数目比1:2,即10行源程序,至少要给出5行注释。
操作系统课程设计实验报告实验一编译Linux内核实验时间6小时实验目的认识Linux内核的组成,掌握配置、编译、安装Linux内核的步骤。
实验目标下载2.6.19或更新的Linux内核,配置该内核使其支持NTFS,并在新的内核中修改其版本为Linux NameTestKernel x.x.x,其中,Name是你的名字(汉语拼音);x.x.x是新内核的版本号,最后在你的机器上编译安装这个新内核。
实验三进程通讯实验报告【姓名】【学号】【实验题目】进程通讯——消息队列与共享存储区【实验目的】(1)掌握进程间通讯的编程方法;(2)加深对进程并发执行的理解;(3)学习利用消息队列和共享存储区实现进程通信的方法。
【实验内容】设计一个多进程并发运行的程序,它由不同的进程完成下列工作:(1)接收键盘输入进程负责接收用户的键盘输入,并以适当的方式将由键盘获得的数据交给其它进程处理。
(2)显示进程负责全部数据显示任务,包括键盘输入数据的显示和提示信息的显示。
(3)分发数据进程将键盘输入的数据分为3类,即字母、数字和其它,并分别将字母写入文件letter.txt 中,数字写入文件number.txt中,除字母和数字外其它数据丢弃。
【实验要求】1、程序能以适当的方式提示用户输入数据;2、提示用户有数据被丢弃;3、全部的显示任务必须由显示进程完成;4、整个程序能够连续处理多组输入数据,直到用户输入“quit”字符串,整个程序结束;5、进一步要求:同时采用共享存储区和消息2种方法实现进程之间的通信,并比较这2种通信方法的利弊。
【实验方法】1、利用fork()函数创建2个子进程,用一个父进程和两个子进程完成上面的三个实验任务,用子进程1实现分发数据任务,子进程2实现接受键盘输入任务,父进程实现全部的显示任务。
2、同时通过共享存储区和消息队列两种进程通讯方式实现上面三个进程之间的同步和互斥。
3、利用while()循环、kill()函数和signal()函数实现连续多组数据输入。
【程序结构】·数据结构:消息队列、字符数组;·程序结构:顺序结构、if-else分支结构和while循环结构;·主要算法:无特别算法【实验结果】1、有代表性的执行结果:[stud13@localhost stud13]$ cc ipc.c[stud13@localhost stud13]$ ./a.outPlease input a line:∟operatingsystem01234-=,.Your message is:operatingsystem01234-=,.The characters deserted are:-=,.Please input a line:∟xushengju6651001!@#$%^&*()Your message is:xushengju6651001!@#$%^&*()The characters deserted are:!@#$%^&*()Please input a line:∟Hello123Your message is:Hello123Please input a line:∟quit[stud13@localhost stud13]$ cat letter.txtOperatingsystemxushengjuHello[stud13@localhost stud13]$ cat number.txt 012346651001123[stud13@localhost stud13]$2、结果分析及解释:在创建子进程1时,由于先返回子进程的ID号,msgrcv(msgid,&msg,BUFSIZE,0,0)一直都是非0值,故循环等待。
电大操作系统实验报告3_ 进程管理实验电大操作系统实验报告 3 进程管理实验一、实验目的进程管理是操作系统的核心功能之一,本次实验的目的是通过实际操作和观察,深入理解进程的概念、状态转换、进程调度以及进程间的通信机制,掌握操作系统中进程管理的基本原理和方法,提高对操作系统的整体认识和实践能力。
二、实验环境本次实验使用的操作系统为 Windows 10,编程语言为 C 语言,开发工具为 Visual Studio 2019。
三、实验内容及步骤(一)进程的创建与终止1、编写一个 C 程序,使用系统调用创建一个子进程。
2、在父进程和子进程中分别输出各自的进程 ID 和父进程 ID。
3、子进程执行一段简单的计算任务,父进程等待子进程结束后输出结束信息。
以下是实现上述功能的 C 程序代码:```cinclude <stdioh>include <stdlibh>include <unistdh>int main(){pid_t pid;pid = fork();if (pid < 0) {printf("创建子进程失败\n");return 1;} else if (pid == 0) {printf("子进程:我的进程 ID 是%d,父进程 ID 是%d\n",getpid(), getppid());int result = 2 + 3;printf("子进程计算结果:2 + 3 =%d\n", result);exit(0);} else {printf("父进程:我的进程 ID 是%d,子进程 ID 是%d\n",getpid(), pid);wait(NULL);printf("子进程已结束\n");}return 0;}```编译并运行上述程序,可以观察到父进程和子进程的输出信息,验证了进程的创建和终止过程。
(二)进程的状态转换1、编写一个 C 程序,创建一个子进程,子进程进入睡眠状态一段时间,然后被唤醒并输出状态转换信息。
操作系统实验3进程的创建控制实验实验三的目标是通过实现一个进程控制程序,来加深我们对进程创建和控制机制的理解,并通过实践来熟悉和掌握相关的编程技巧。
在进行实验之前,我们需要先了解进程的一些基本概念和相关知识。
首先,进程的创建是通过操作系统中的系统调用来完成的。
在Linux系统中,常用的创建进程的系统调用有fork(和exec(。
fork(系统调用可以创建一个新的进程,该进程与调用fork(的进程几乎完全相同;而exec(系统调用则在新创建的进程中执行一个新的程序。
另外,进程的控制机制主要是通过进程的状态来实现的。
进程可以处于就绪状态、运行状态和阻塞状态。
就绪状态的进程可以被调度器选择后立即运行,而阻塞状态的进程则需要等待一些条件满足后才能被唤醒并变为就绪状态。
实验三的具体内容包括:1. 编写一个程序,通过调用fork(创建多个子进程。
子进程和父进程可以并行执行,共享程序的代码和数据段。
2. 子进程通过调用exec(系统调用执行不同的程序。
可以通过调用不同的exec(函数或者传入不同的参数来执行不同的程序。
3. 子进程执行的程序可能会产生不同的结果,比如输出不同的字符串或者产生不同的返回值。
我们可以通过wait(系统调用等待子进程退出,并获取子进程的返回值。
4. 父进程可以通过调用waitpid(系统调用来选择等待一些特定的子进程,以及获取特定子进程的返回值。
通过实验三的实践,我将更加深入地了解进程的创建和控制机制。
实验三的实验结果将让我熟悉和掌握相关的编程技巧,为我今后更加熟练地编写和控制进程打下坚实的基础。
总之,实验三是一个非常有意义的实验,将帮助我更加深入地理解进程的创建和控制机制,并通过实践获得相关的编程技巧。
这将对我今后的学习和实践有很大的帮助。
操作系统实验报告试验一:进程创建与撤销计科112康岩岩2011008142202013/4/10实验一:进程创建与撤消一、实验目的1、加深对进程概念的理解和进程创建与撤消算法;2、进一步认识并发执行的实质。
二、实验内容本实验完成如下三个层次的任务:(1)系统级—以普通用户身份认识windows的进程管理。
通过windows的“任务管理器”观察进程的状态,进行进程的创建、切换和撤销。
(2)语言级—以普通程序员身份认识高级语言VC++/Java/C#的进程创建与撤销工具。
(3)模拟级—以OS设计师身份编程模拟实现进程创建与撤销功能,并在屏幕上观察进程活动的结果。
三、实验步骤1、windows的进程管理以下是win7的人物管理器,可以进行进程的查看、创建、撤销等操作,由于操作比较简单与琐碎,这里不再具体描述。
2、VC++/Java/C#的进程创建与撤销工具对于本次试验,我使用C#进行进程创建、撤销等测试,具体内容在下面给出。
3、进程创建与撤销的模拟实现(1)总体设计:此次程序完全由c#实现,能够通过窗体界面详细地生动地显示进程的运行状态。
下面一步一步的进行实现①数据定义:类PCB的定义如下:class PCB{string pcbName; //进程名int pcbId; //IDlong startTime; //开始时间long pcbRuntime = 0; //运行时间int pcbLeve; //线程优先级}对于所有的进程信息,用以下表储存:Dictionary<int,Hashtable>ThreadTable=new Dictionary<int,Hashtable>();容器ThreadTable用来储存所有进程简直key 表示进程id,值为Hashtable,储存的为线程信息,②函数CREATE(PCB pcb)—进程创建:创建进程需要传入一个PCB 对象,然后启动一个单独的线程来操作该对象,操作该对象就是把线程运行的状态传送给PCB同时PCB也唯一地标示其所在的线程。
一、实验目的1. 理解进程的概念和特点。
2. 掌握创建进程的方法和过程。
3. 熟悉进程调度和同步机制。
4. 分析进程创建过程中可能遇到的问题及解决方法。
二、实验环境1. 操作系统:Windows 102. 编程语言:C/C++3. 开发工具:Visual Studio 2019三、实验原理进程是操作系统中进行资源分配和调度的基本单位。
创建进程是操作系统提供的一项基本功能,它允许用户在系统中启动新的程序。
在创建进程的过程中,操作系统会为进程分配一定的资源,如内存、文件句柄等。
四、实验内容1. 创建进程2. 父子进程的同步3. 进程的终止五、实验步骤1. 创建进程(1)编写C/C++程序,使用系统调用创建进程。
(2)父进程调用`fork()`函数创建子进程。
(3)在子进程中执行特定任务。
(4)父进程和子进程分别调用`wait()`函数等待对方结束。
2. 父子进程的同步(1)父进程和子进程使用信号量实现同步。
(2)父进程调用`sem_wait()`函数等待信号量。
(3)子进程调用`sem_post()`函数释放信号量。
3. 进程的终止(1)父进程调用`kill()`函数终止子进程。
(2)子进程调用`exit()`函数结束进程。
六、实验结果与分析1. 创建进程(1)在父进程中调用`fork()`函数创建子进程。
(2)父进程和子进程分别输出“父进程”和“子进程”信息。
实验结果:```父进程子进程```2. 父子进程的同步(1)父进程和子进程使用信号量实现同步。
(2)父进程调用`sem_wait()`函数等待信号量。
(3)子进程调用`sem_post()`函数释放信号量。
实验结果:```父进程子进程```3. 进程的终止(1)父进程调用`kill()`函数终止子进程。
(2)子进程调用`exit()`函数结束进程。
实验结果:```父进程子进程```七、实验总结通过本次实验,我们掌握了以下内容:1. 进程的概念和特点。
(1)首先查找调用进程是否有子进程,若无,则返回出错码;(2)若找到一处于“僵死状态”的子进程,则将子进程的执行时间加到父进程的执行时间上,并释放子进程的进程表项;(3)若未找到处于“僵死状态”的子进程,则调用进程便在可被中断的优先级上睡眠,等待其子进程发来软中断信号时被唤醒。
4、exit()终止进程的执行。
系统调用格式:void exit(status)int status;其中,status 是返回给父进程的一个整数,以备查考。
为了及时回收进程所占用的资源并减少父进程的干预,LINUX/LINUX 利用exit( )来实现进程的自我终止,通常父进程在创建子进程时,应在进程的末尾安排一条exit( ),使子进程自我终止。
exit(0)表示进程正常终止,exit(1)表示进程运行有错,异常终止。
如果调用进程在执行exit( )时,其父进程正在等待它的终止,则父进程可立即得到其返回的整数。
核心须为exit( )完成以下操作:(1)关闭软中断(2)回收资源(3)写记帐信息(4)置进程为“僵死状态”参考程序#include<stdio.h>#include<unistd.h>main( ){in t pid;pid=fork( ); /*创建子进程*/switch(pid){case -1:printf("fork fail!\n");exit(1);case 0: /*创建失败*//*子进程*/execl("/bin/ls","ls","1","color",NULL); printf("exec fail!\n");exit(1);default:wait(NULL);/*父进程*/ /*同步*/printf("ls completed !\n");exit(0);}}运行结果执行命令ls -l -color ,(按倒序)列出当前目录下所有文件和子目录;ls completed!分析原因程序在调用fork( )建立一个子进程后,马上调用wait( ),使父进程在子进程结束之前,一直处于睡眠状态。
进程管理实验报告进程管理实验报告引言:进程管理是操作系统中的重要概念,它负责调度和控制计算机系统中的各个进程,确保它们能够有序地执行。
本实验旨在通过实际操作和观察,深入了解进程管理的原理和方法,并通过实验结果分析其影响因素和优化策略。
实验一:进程创建与终止在本实验中,我们首先进行了进程的创建和终止实验。
通过编写简单的程序,我们能够观察到进程的创建和终止过程,并了解到进程控制块(PCB)在其中的作用。
实验结果显示,当一个进程被创建时,操作系统会为其分配一个唯一的进程ID,并为其分配必要的资源,如内存空间、文件描述符等。
同时,操作系统还会为该进程创建一个PCB,用于存储该进程的相关信息,如进程状态、程序计数器等。
当我们手动终止一个进程时,操作系统会释放该进程所占用的资源,并将其PCB从系统中删除。
这样,其他进程便可以继续使用这些资源,提高系统的效率和资源利用率。
实验二:进程调度算法进程调度算法是决定进程执行顺序的重要因素。
在本实验中,我们通过模拟不同的进程调度算法,比较它们在不同场景下的表现和效果。
我们选择了三种常见的进程调度算法:先来先服务(FCFS)、最短作业优先(SJF)和轮转调度(RR)。
通过设置不同的进程执行时间和优先级,我们观察到不同调度算法对系统吞吐量和响应时间的影响。
实验结果显示,FCFS算法适用于执行时间较短的进程,能够保证公平性,但在执行时间较长的进程出现时,会导致等待时间过长,影响系统的响应速度。
SJF 算法在执行时间较长的进程时表现出色,但对于执行时间较短的进程,可能会导致饥饿现象。
RR算法能够在一定程度上平衡各个进程的执行时间,但对于执行时间过长的进程,仍然会影响系统的响应速度。
实验三:进程同步与互斥在多进程环境中,进程之间的同步和互斥是必不可少的。
在本实验中,我们通过模拟进程间的竞争和互斥关系,观察进程同步与互斥的实现方式和效果。
我们选择了信号量机制和互斥锁机制作为实现进程同步和互斥的方法。
计算机系统基础实验计算机系统基础实验是计算机科学与技术专业中的一门重要课程,旨在帮助学生深入理解计算机硬件和操作系统的工作原理,培养学生的实际操作能力。
以下是一个关于计算机系统基础实验的报告,详细介绍了关于进程管理和内存管理的实验过程和结果。
实验题目:进程管理和内存管理一、实验目的:1.熟悉进程的创建、运行和撤销过程;2.理解进程之间的关系和调度算法;3.掌握内存管理的基本原理和常用方法。
二、实验环境:1. 操作系统:Windows 10;2. 虚拟机软件:VMware Workstation 16 Pro;3.编程语言:C/C++。
三、实验内容和过程:实验一:进程的创建、运行和撤销1.实验步骤:(1)使用C/C++编写一个创建进程的程序,包括进程的标识符、优先级和资源需求等;(2)编译并运行程序,查看进程的创建情况;(3)编写一个进程调度算法程序,选择一个合适的调度算法,并设置相应的调度策略;(4)编译并运行进程调度算法程序,观察进程的执行情况;(5)撤销一个进程,并查看撤销后的进程状态。
2.实验结果:(1)成功创建了一个进程,并查看到相关信息;(2)进程调度算法程序成功运行,并根据所设置的策略进行调度;(3)成功撤销一个进程,并查看到撤销后的进程状态。
实验二:内存管理1.实验步骤:(1)使用C/C++编写一个内存分配算法程序,包括内存的分配和回收等功能;(2)编译并运行程序,查看内存的分配情况;(3)使用一个合适的页面置换算法,编写一个程序来模拟分页机制的内存管理;(4)编译并运行分页程序,观察页面置换的情况;(5)释放内存,并查看内存的回收情况。
2.实验结果:(1)成功分配了内存,并查看到相关信息;(2)分页程序成功运行,并根据所选择的页面置换算法进行置换;(3)成功回收内存,并查看到内存的回收情况。
四、实验总结:通过这次实验,我们深入了解了进程的创建、运行和撤销过程,以及进程之间的关系和调度算法。
实验三进程的创建实验[实验目的及要求]1.掌握进程的概念,明确进程的含义;2.认识并了解并发执行的实质;3.理解LINUX下进程创建的基本方法和过程。
[实验原理]一、进程UNIX中,进程既是一个独立拥有资源的基本单位,又是一个独立调度的基本单位。
一个进程实体由若干个区(段)组成,包括程序区、数据区、栈区、共享存储区等。
每个区又分为若干页,每个进程配置有唯一的进程控制块PCB,用于控制和管理进程。
PCB的数据结构如下:1.进程表项(Process Table Entry)。
包括一些最常用的核心数据:进程标识符PID、用户标识符UID、进程状态、事件描述符、进程和U区在内存或外存的地址、软中断信号、计时域、进程的大小、偏置值nice、指向就绪队列中下一个PCB 的指针P_Link、指向U区进程正文、数据及栈在内存区域的指针。
2.U区(U Area)。
用于存放进程表项的一些扩充信息。
每一个进程都有一个私用的U区,其中含有:进程表项指针、真正用户标识符u-ruid(read user ID)、有效用户标识符u-euid(effective user ID)、用户文件描述符表、计时器、内部I/O参数、限制字段、差错字段、返回值、信号处理数组。
由于UNIX系统采用段页式存储管理,为了把段的起始虚地址变换为段在系统中的物理地址,便于实现区的共享,所以还有:3.系统区表项。
以存放各个段在物理存储器中的位置等信息。
系统把一个进程的虚地址空间划分为若干个连续的逻辑区,有正文区、数据区、栈区等。
这些区是可被共享和保护的独立实体,多个进程可共享一个区。
为了对区进行管理,核心中设置一个系统区表,各表项中记录了以下有关描述活动区的信息:区的类型和大小、区的状态、区在物理存储器中的位置、引用计数、指向文件索引结点的指针。
4.进程区表系统为每个进程配置了一张进程区表。
表中,每一项记录一个区的起始虚地址及指向系统区表中对应的区表项。
核心通过查找进程区表和系统区表,便可将区的逻辑地址变换为物理地址。
二、进程映像UNIX系统中,进程是进程映像的执行过程,也就是正在执行的进程实体。
它由三部分组成:1.用户级上、下文。
主要成分是用户程序;2.寄存器上、下文。
由CPU中的一些寄存器的内容组成,如PC,PSW,SP及通用寄存器等;3.系统级上、下文。
包括OS为管理进程所用的信息,有静态和动态之分。
三、所涉及的系统调用1.fork( )创建一个新进程。
系统调用格式:pid=fork( )参数定义:int fork( )fork( )返回值意义如下:0:在子进程中,pid变量保存的fork( )返回值为0,表示当前进程是子进程。
>0:在父进程中,pid变量保存的fork( )返回值为子进程的pid值(进程唯一标识符)。
-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( )返回值的不同,执行了不同的分支语句。
[实验内容及步骤]1.编写一段程序,使用系统调用fork( )创建两个子进程。
当此程序运行时,在系统中有一个父进程和两个子进程活动。
让每一个进程在屏幕上显示一个字符:父进程显示'a',子进程分别显示字符'b'和字符'c'。
试观察记录屏幕上的显示结果,并分析原因。
2.修改上述程序,每一个进程循环显示一句话。
子进程显示'daughter …'及'son ……',父进程显示'parent ……',观察结果,分析原因。
[实验指导]一、参考程序实验步骤一:#include <stdio.h>main( ){int p1,p2;printf(“\n”);while((p1=fork( ))= = -1); /*创建子进程p1*/if (p1= =0) putchar('b');else{while((p2=fork( ))= = -1); /*创建子进程p2*/if(p2= =0) putchar('c');else putchar('a');}}实验步骤二:#include <stdio.h>main( ){int p1,p2,i;while((p1=fork( ))= = -1); /*创建子进程p1*/if (p1= =0)for(i=0;i<10;i++)printf("daughter %d\n",i);else{while((p2=fork( ))= = -1); /*创建子进程p2*/if(p2= =0)for(i=0;i<10;i++)printf("son %d\n",i);elsefor(i=0;i<10;i++)printf("parent %d\n",i);}}二、运行结果1.bca,bac, abc ,……都有可能。
2.parent…son…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)程序要结果要反复执行多次才能看出规律。
[实验报告要求](1)阅读LINUX的fork.c源码文件(部份),分析进程的创建过程。
(2)阅读LINUX的sched.c源码文件(部份),加深对进程管理概念的认识。
(3)设计完成上述要求的C程序,并编译、执行,观查并分析结果。
[参考资料]附录二/USR/SRC/LINUX/KERNEL/FORK.C#INCLUDE <ERRNO.H>#INCLUDE <LINUX/SCHED.H>#INCLUDE <LINUX/KERNEL.H>#INCLUDE <ASM/SEGMENT.H>#INCLUDE <ASM/SYSTEM.H>EXTERN VOID WRITE_VERIFY(UNSIGNED LONG ADDRESS) ;LONG LAST_PID = 0; //最新进程号,其值会由GET_EMPTY_PROCESS生成VOID VERIFY_AREA(VOID * ADDR , INT SIZE){UNSIGNED LONG START ;START = (UNSIGNED LONG) ADDR ;SIZE += START & 0XFFF ;START &= 0XFFFFF000 ;START += GET_BASE(C URRENT->LDT[2]) ;WHILE(SIZE > 0){SIZE -= 4096 ;WRITE_VERIFY(START) ;START += 4096 ;}}//该函数为新的进程在线性地址空间中设置新的代码段和数据段基地址和限长INT COPY_MEM(INT NR , STRUC T TASK_STRUC T * P){UNSIGNED LONG OLD_DATA_BASE , NEW_DATA_BASE , DATA_LIMIT ;UNSIGNED LONG OLD_CODE_BASE , NEW_CODE_BASE , CODE_LIMIT ;CODE_LIMIT = GET_LIMIT(0X0F) ;DATA_LIMIT = GET_LIMIT(0X17) ;OLD_CODE_BASE = GET_BASE(C URRENT->LDT[1]) ;OLD_DATA_BASE = GET_BASE(C URRENT->LDT[2]) ;IF(OLD_CODE_BASE != OLD_DATA_BASE)PANIC("WE DONOT SUPPORT SEPERATE ID") ;IF(DATA_LIMIT < CODE_LIMIT)PANIC("BAD DATA_LIMIT") ;NEW_DATA_BASE = NEW_CODE_BASE = NR * 0X4000000 ; //NR * 64 MBP->START_CODE = NEW_CODE_BASE ;SET_BASE(P->LDT[1] , NEW_CODE_BASE) ;SET_BASE(P->LDT[2] , NEW_DATA_BASE) ;IF(COPY_PAGE_TABLES(OLD_DATA_BASE , NEW_DATA_BASE , DATA_ LIMIT)){FREE_PAGE_TABLES(NEW_DATA_BASE , DATA_LIMIT) ;RETURN -ENOMEM ;}RETURN 0 ;}//下面是主要的FORK程序,负责复制系统进程信息//并且设置必要的寄存器,还整个地复制数据段INT COPY_PROCESS(INT NR , LONG EBP , LONG EDI , LONG ESI , LONG G S , LONG NONE ,LONG EBX , LONG ECX , LONG EDX , LONG FS , LONG ES , LONG DS , LO NG EIP ,LONG CS , LONG EFLAGS , LONG ESP , LONG SS){STRUC T TASK_STRUC T * P ;INT I ;STRUC T FILE * F ;P = (STRUC T TASK_STRUC T *) GET_FREE_PAGE() ;IF(!P)RETURN -EAGAIN ;TASK[NR] = P ;*P = * C URRENT ; //并不是指针的赋值,而是直接申请了一个空间//下面开始修改任务数据结构的值P->STATE = TASK_UNINTERRUPTIBLE ;P->PID = LAST_PID ;P->FATHER = C URRENT->PID ;P->COUNTER = P->PRIORITY ;//设置时间片P->SIGNAL = 0 ; //信号位图置0P->ALARM = 0 ; //报警定时器值P->LEADER = 0 ;//进程的领导权P->UTIME = P->STIME = 0 ; //用户态号和核心态的运行时间P->CUTIME = P->CSTIME = 0 ;//子进程用户态和和核心态的运行时间P->START_TIME = JIFFIES ; //进程当前的运行时间P->TSS.BAC K_LINK = 0 ;P->TSS.ESP0 = PAGE_SIZE + (LONG) P ; //任务内核态栈指针P->TSS.SS0 = 0X10 ; //内核态的段选择符,与数据段选择符相同P->TSS.EIP = EIP ;P->TSS.EFLAGS = EFLAGS ;P->TSS.EAX = 0 ; //这是当FORK()调用返回时新进程会返回0的原因P->TSS.ECX = ECX ;P->TSS.EDX = EDX ;P->TSS.EBX = EBX ;P->TSS.ESP = ESP ;P->TSS.EBP = EBP ;P->TSS.ESI = ESI ;P->TSS.EDI = EDI ;P->TSS.ES = ES & 0XFFFF ;P->TSS.CS = CS & 0XFFFF ;P->TSS.SS = SS & 0XFFFF ;P->TSS.DS = DS & 0XFFFF ;P->TSS.FS = FS & 0XFFFF ;P->TSS.GS = GS & 0XFFFF ;P->TSS.LDT = _LDT(NR) ;P->TSS.TRACE_BITMAP = 0X80000000 ;IF(LAST_TASK_USED_MATH == C URRENT)__ASM__("CLTS ; FNSAVE %0" ::"M"(P->TSS.I387)) ;//接下来复制进程页表,即在线性地址空间设置新任务代码段和数据段描述符中的基地址和限长,并复制页表。