OS综合实验报告1.docx
《OS综合实验报告1.docx》由会员分享,可在线阅读,更多相关《OS综合实验报告1.docx(29页珍藏版)》请在冰豆网上搜索。
![OS综合实验报告1.docx](https://file1.bdocx.com/fileroot1/2023-5/24/0acfb7c0-076f-4479-aadd-2aaebfcd4c2a/0acfb7c0-076f-4479-aadd-2aaebfcd4c2a1.gif)
OS综合实验报告1
综合实验报告
(2013--2014年度第1学期)
名称:
操作系统综合实验
题目:
基于OSLab的操作系统综合实验
院系:
计算机系
班级:
学号:
学生姓名:
指导教师:
王德文,王艳
设计周数:
1
成绩:
日期:
2013年月日
一、课程设计(综合实验)的目的与要求
1.正文为宋体,五号字行间距为21
1.1------------
1.2------------
二、设计(实验)正文
1.正文为宋体,五号字行间距为21
1.1------------
1.2------------
三、课程设计(综合实验)总结或结论
1.正文为宋体,五号字行间距为21
1.1------------
1.2------------
四、参考文献
[1]作者1,作者2书名.出版单位,版本.出版日期
附录(设计流程图、程序、表格、数据等)
一.实验环境的使用
1.实验目的
●熟悉操作系统集成实验环境OSLab的基本使用方法。
●练习编译、调试EOS操作系统内核以及EOS应用程序。
2.实验内容:
.学习OSLab的基本使用方法
a.启动OSlab
b.新建windows控制台程序项目,eos内核项目,eos应用程序项目;
c.生成项目
d.执行项目
e.调试项目
f.项目名称的修改及项目的保存
.实验中代码的修改:
1)在func.c文件中添加函数:
intFunc(intn){n=n+1;returnn;}
2)点击源代码编辑器上方的console.c标签,切换到console.c文件。
将main函数修改为:
intmain(intargc,char*argv[])
{
intFunc(intn);//声明Func函数
intn=0;
n=Func(10);
printf("HelloWorld!
\n");
return0;
}
问题答案:
EOSSDk文件夹的目的和作用:
主要供EOS应用程序使用。
EOS内核提供的API函数及重要的数据类型都是通过将相关的头文件复制到SDK文件夹中,然后EOS应用程序再包含SDK文件夹中的头文件,使EOS应用程序可以调用这些函数或使用数据类型来定义变量。
同时,SDK文件夹中还保存了Debug和Release版本的二进制文件,分别为两个版本的应用程序使用。
运行结果图示
实验总结及体会:
通过本次实验,对EOS操作系统和OSLab集成实验环境有一个初步的了解,学会了创建三种项目,项目的调试,执行及保存,还有一些文件的含义。
实验三.进程创建
1.实验目的:
练习使用EOSAPI函数CreateProcess创建一个进程,掌握创建进程的方法,理解进程和程序的区别。
试跟踪CreateProcess函数的执行过程,了解进程的创建过程,理解进程是资源分配的单位。
2.实验内容:
练习使用控制台命令创建EOS应用程序的进程;
练习通过编程的方式让应用程序创建另一个应用程序的进程;
调试CreateProcess函数;
调试PsCreateProcess函数;
练习通过编程的方式创建应用程序的多个进程。
实验中修改的代码:
1.#include"EOSApp.h"
intmain(intargc,char*argv[])
{
inti;
for(i=1;i<=5;i++){
printf("Hello,world!
%d\n",i);
Sleep(1000);
}
printf("Bye-bye!
\n");
return0;
}
2./*
#include"EOSApp.h"
intmain(intargc,char*argv[])
{STARTUPINFOStartupInfo;
PROCESS_INFORMATIONProcInfo;
ULONGulExitCode;//子进程退出码
INTnResult=0;//main函数返回值。
0表示成功,非0表示失败。
#ifdef_DEBUG
__asm("int$3\nnop");
#endif
printf("Createaprocessandwaitfortheprocessexit...\n\n");
StartupInfo.StdInput=GetStdHandle(STD_INPUT_HANDLE);
StartupInfo.StdOutput=GetStdHandle(STD_OUTPUT_HANDLE);
StartupInfo.StdError=GetStdHandle(STD_ERROR_HANDLE);
if(CreateProcess("A:
\\Hello.exe",NULL,0,&StartupInfo,&ProcInfo)){
WaitForSingleObject(ProcInfo.ProcessHandle,INFINITE);
GetExitCodeProcess(ProcInfo.ProcessHandle,&ulExitCode);
printf("\nTheprocessexitwith%d.\n",ulExitCode);
CloseHandle(ProcInfo.ProcessHandle);
CloseHandle(ProcInfo.ThreadHandle);
}else{
printf("CreateProcessFailed,Errorcode:
0x%X.\n",GetLastError());
nResult=1;
}
returnnResult;
}
3./*
#include"EOSApp.h"
intmain(intargc,char*argv[])
{
STARTUPINFOStartupInfo;
PROCESS_INFORMATIONProcInfoOne,ProcInfoTwo;
ULONGulExitCode;//子进程退出码
INTnResult=0;//main函数返回值。
0表示成功,非0表示失败。
#ifdef_DEBUG
__asm("int$3\nnop");
#endif
printf("Createtwoprocessesandwaitfortheprocessesexit...\n\n");
StartupInfo.StdInput=GetStdHandle(STD_INPUT_HANDLE);
StartupInfo.StdOutput=GetStdHandle(STD_OUTPUT_HANDLE);
StartupInfo.StdError=GetStdHandle(STD_ERROR_HANDLE);
if(CreateProcess("A:
\\Hello.exe",NULL,0,&StartupInfo,&ProcInfoOne)
&&CreateProcess("A:
\\Hello.exe",NULL,0,&StartupInfo,&ProcInfoTwo)){
WaitForSingleObject(ProcInfoOne.ProcessHandle,INFINITE);
WaitForSingleObject(ProcInfoTwo.ProcessHandle,INFINITE);
GetExitCodeProcess(ProcInfoOne.ProcessHandle,&ulExitCode);
printf("\nTheprocessoneexitwith%d.\n",ulExitCode);
GetExitCodeProcess(ProcInfoTwo.ProcessHandle,&ulExitCode);
printf("\nTheprocesstwoexitwith%d.\n",ulExitCode);
CloseHandle(ProcInfoOne.ProcessHandle);
CloseHandle(ProcInfoOne.ThreadHandle);
CloseHandle(ProcInfoTwo.ProcessHandle);
CloseHandle(ProcInfoTwo.ThreadHandle);
}else{
printf("CreateProcessFailed,Errorcode:
0x%X.\n",GetLastError());
nResult=1;
}
returnnResult;
}
问题解答:
PspCreateProcessEnvironment函数的主要功能是创建进程控制块,并且为进程创建了地址空间和分配了句柄表,PspLoadProcessImage是将进程的可执行映像加载到了进程的地址空间中。
PspCreateThread创建了进程的主线程。
这三个函数的被调用顺序是不能改变的,就像上面所描述的,加载可执行文件之前必须已经为进程创建地址空间,这样才能确定可执行映像可以被加载到内存的什么位置,在创建主线程之前必须已经加载了可执行映像,这样主线程才能够知道自己从哪里开始执行,执行那些命令。
实验中一些运行结果
实验总结:
通过本次实验了解到当EOS应用程序eosapp.exe存储在软盘上的时候,它是静态的,只包含应用程序的指令和数据。
而创建进程后,进程不但包含应用程序的指令和数据,也会包含操作系统内核(kernel.dll)的指令和数据,同时也了解到一个进程可以包含多个程序,就该实验而言:
该进程包含了eosapp.exe和kernel.dll两个程序。
进程的创建过程:
当EOS创建一个进程时,会首先创建一个进程对象,并且进程对象的对象体使用的就是PCB结构体。
接下来,操作系统会为进程分配一个进程地址空间和一个句柄表。
一般情况下,每个进程都是由一个可执行文件(后缀名为EXE的文件)来创建的,所以,操作系统会将可执行文件装入进程地址空间的用户地址空间中,并和内核地址空间中的内核进行动态链接(DynamicLink)。
最后,操作系统会为进程创建一个主线程,并使主线程从进程可执行文件的入口点开始执行。
实验四.线程的状态和转换
1.实验及目的
调试线程在各种状态间的转换过程,熟悉线程的状态和转换。
通过为线程增加挂起状态,加深对线程状态的理解。
2.实验内容
准备实验
调试线程状态的转换过程
准备工作
A、查看loop命令执行的效果
B调试线程状态转换的过程:
、
C、对断点进行一些调整:
(三)、为线程增加挂起状态
加入的代码;
STATUS
PsResumThread(
INHANDLEhThread
)
{
STATUSStatus;
BOOLIntState;
PTHREADThread;
Status=ObRefObjectByHandle(hThread,PspThreadType,(PVOID*)&Thread);
if(EOS_SUCCESS(Status)){
IntState=KeEnableInterrupts(FALSE);//关中断
if(Zero==Thread->State){
Status=STATUS_SUCCESS;
}else{
Status=STATUS_NOT_SUPPORTED;
}
KeEnableInterrupts(IntState);//开中断
ObDerefObject(Thread);
}
returnStatus;
}
问题解答:
当在控制台2中执行suspend命令时,实质上是优先级为24的控制台2线程抢占了处理器,也就是控制台2线程处于运行状态,所以此时loop线程处于就绪状态了。
实验总结
通过本次实验,调试线程在各种状态间的转换过程,熟悉了线程的状态和转换。
通过为线程增加挂起状态,加深了对线程状态的理解。
了解到EOS线程状态有就绪状态、阻塞状态、运行状态。
以及其状态的转换过程有新建→就绪、就绪→运行、运行→就绪、运行→阻塞、阻塞→就绪、任意状态→结束状态六种,以及Suspend和Resume原语操作使其进入挂起和唤醒状态。
实验五.进程的同步
1.实验目的
使用EOS的信号量,编程解决生产者—消费者问题,理解进程同步的意义。
调试跟踪EOS信号量的工作过程,理解进程同步的原理。
修改EOS的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。
2.实验内容
准备实验
使用EOS的信号量解决生产者-消费者问题
调试EOS信号量的工作过程
修改EOS的信号量算法:
STATUS
PsWaitForSemaphore(
INPSEMAPHORESemaphore,
INULONGMilliseconds
)
返回值:
STATUS_SUCCESS。
当你修改信号量使之支持超时唤醒功能后,如果等待超时,应该返回STATUS_TIMEOUT。
{
STATUSstatus;
BOOLIntState;
ASSERT(KeGetIntNesting()==0);IntState=KeEnableInterrupts(FALSE);//开始原子操作,禁止中断。
if(Semaphore->Count>0){
Semaphore->Count--;
status=STATUS_SUCCESS;
}
if(Semaphore->Count==0){
status=PspWait(&Semaphore->WaitListHead,Milliseconds);
}
KeEnableInterrupts(IntState);//原子操作完成,恢复中断。
returnstatus;
}
在PsReleaseSemaphore函数中修改为:
for(Semphore->Count+=RealeaseCount;Semphore->Count>0&&!
ListisEmpty(&Semphore->WaitListHead);Semphore->Count--){
PspWakeThread(&Semphore->WaitListHead,STATUS_SUCCESS)}
问题回答:
Mutex对象只是用来保护临界资源的,放置生产者线程和消费者线程同时访问临界资源,从而造成混乱,Empty信号量和Full信号量是相互合作不可分割的,在生产者线程中,Empty信号量保证没有在空缓冲区的时候让生产者停止生产,Full信号量保证在生产完毕一个产品后增加一个满缓冲区;消费者线程中,full信号量保证在没有满缓冲区的时候让消费者停止消费,Empty信号量保证在消费完毕一个产品增加一个空缓冲区,所以顺序不能改变。
实验总结
通过本次实验我更加了解了进程的同步的主要任务是使并发执行的各进程之间能有效的共享资源和相互合作。
并且对进程同步的原理理解的更加透彻,并且了解到可以使用互斥体(Mutex)、信号量(Semophore)和事件(Event)等同步对象来解决一系列经典的进程同步问题。
实验六.时间片轮转调度
1.实验目的
调试EOS的线程调度程序,熟悉基于优先级的抢先式调度。
为EOS添加时间片轮转调度,了解其它常用的调度算法。
2.实验内容
准备实验
阅读控制台命令“rr”相关的源代码
调试线程调度程序
(1).调试当前线程不被抢先的情况
(2)、调试当前线程被抢先的情况
为EOS添加时间片轮转调度
(1)修改ps/sched.c文件中的PspRoundRobin函数
VOID
PspRoundRobin(
VOID
)
{
if(NULL!
=PspCurrentThread&&Running==PspCurrentThread->State){
PspCurrentThread->RemainderTicks--;
if(0==PspCurrentThread->RemainderTicks){
PspCurrentThread->RemainderTicks=TICKS_OF_TIME_SLICE;
if(BIT_TEST(PspReadyBitmap,PspCurrentThread->Priority)){
PspReadyThread(PspCurrentThread);
}
}
}
}
问题解答:
如果使用互斥信号量,则那些由于访问临界区而被阻塞的线程,就会被放入互斥信号量的等待队列,就不会再相应优先级的就绪队列中了,而时间片轮转调度算法就是对就绪队列的线程进行轮转调度,而不是对被阻塞线程调度的。
实验总结;
通过本次实验了解到时间片的大小对时间片轮转调度有着一定的影响。
当时间片过长时,调度算法退化为FCFS算法,不利于短作业的调用;而当时间片过短时,则会使进程的切换次数增加,时系统开销增大。
所以说时间片的大小要根据实际情况划分,不可过长,也不可过短。
在这次实验中我感悟到要验证结论必须要进行多次重复的实验,要有耐性,不能只是做几组,这样对结论的验证不具有代表性,应该在不同区域段选取多组值进行验证。
实验七.物理存储器与进程逻辑地址空间的管理
1.实验目的
通过查看物理存储器的使用情况,并练习分配和回收物理内存,从而掌握物理存储器的管理方法。
通过查看进程逻辑地址空间的使用情况,并练习分配和回收虚拟内存,从而掌握进程逻辑地址空间的管理方法。
2.实验内容
准备实验
阅读控制台命令“pm”相关的源代码,并查看其执行的结果
分配物理页和释放物理页
阅读控制台命令“vm”相关的源代码,并查看其执行的结果
在系统进程中分配虚拟页和释放虚拟页
修改的代码
#include"EOSApp.h"
intmain(intargc,char*argv[])
{
#ifdef_DEBUG
__asm("int$3\nnop");
#endif
printf("Endlessloop!
\n");
for(;;){
}
return0;
}
Pm.c//
PRIVATE
VOID
ConsoleCmdPhysicalMemory(
INHANDLEStdHandle
)
{
BOOLIntState;
ULONG_PTRPfnArray[1];
IntState=KeEnableInterrupts(FALSE);//关中断
fprintf(StdHandle,"PageCount:
%d.\n",MiTotalPageFrameCount);
fprintf(StdHandle,"MemoryCount:
%d*%d=%dByte.\n",
MiTotalPageFrameCount,PAGE_SIZE,
MiTotalPageFrameCount*PAGE_SIZE);
fprintf(StdHandle,"\nZeroedPageCount:
%d.\n",MiZeroedPageCount);
fprintf(StdHandle,"FreePageCount:
%d.\n",MiFreePageCount);
fprintf(StdHandle,"\nUsedPageCount:
%d.\n",MiTotalPageFrameCount-MiZeroedPageCount-MiFreePageCount);
MiAllocateAnyPages(1,PfnArray);
fprintf(StdHandle,"\n******AfterAllocateOnePage******\n");
fprintf(StdHandle,"ZeroedPageCount:
%d.\n",MiZeroedPageCount);
fprintf(StdHandle,"FreePageCount:
%d.\n",MiFreePageCount);
fprintf(StdHandle,"UsedPageCount:
%d.\n",MiTotalPageFrameCount-MiZeroedPageCount-MiFreePageCount);
MiFreePages(1,PfnArray);
fprintf(StdHandle,"\n******AfterFreeOnePage******\n");
fprintf(StdHandle,"ZeroedPageCount:
%d.\n",MiZeroedPageCount);
fprintf(StdHandle,"FreePageCount:
%d.\n",MiFreePageCount);
fprintf(StdHandle,"UsedPageCount:
%d.\n",MiTotalPageFrameCount-MiZeroedPageCount-MiFreePageCount);
KeEnableInterrupts(IntState);//开中断
}
问题解答;
从性能角度分析,调用MilAllocateAnyPages函数分配物理页在某些情况下比调用MiAllocateZeroedPages函数要快速。
从安全角度分析,分配零页更加安全。
实验总结
本次实验基本达到了实验目的,通过本次试验我学会了通过查看物理存储器的使用情况,并练习分配和回收物理内存,从而掌握物理存储器的分页式的管理方法。
以及通过查看进程逻辑地址空间的使用情况,并练习分配和回收虚拟内存,从而掌握进程逻辑地址空间的符号链管理方法。
实验八.分页存储器管理
一、实验目的
学习i386处理器的二级页表硬件机制,理解分页存储器管理原理。
查看EOS应用程序进程和系统进程的二级页表映射信息,理解页目录和页表的管理方式。
编程修改页目录和页表的映射关系,理解分页地址变换原理。
2.实验内容
准备实验
查看EOS应用程序进程的页目录和页表
查看应用程序进程和系统进程并