上机实践报告Project2.docx
《上机实践报告Project2.docx》由会员分享,可在线阅读,更多相关《上机实践报告Project2.docx(31页珍藏版)》请在冰豆网上搜索。
上机实践报告Project2
操作系统实践报告
课程名称:
操作系统实践
年级:
12
上机实践成绩:
指导教师:
全红艳
姓名:
修阳
上机实践名称:
PintosProject2
学号:
10122510325
上机实践日期:
上机实践编号:
No.4
组号:
上机实践时间:
一、目的
1)了解Pintos的现有用户程序处理的功能
2)了解Pintos提供的用户程序处理源代码
3)完善Pintos的用户程序处理的功能
二、内容与设计思想
1、掌握Pintos的磁盘申请、复制等功能
2、明确Pintos的用户程序处理中存在的问题
3、具体完成以下功能
(a)进程终止时输出信息
(b)参数功能
(c)系统调用功能
(d)禁止对可执行文件的写入功能
4、撰写实验报告及项目说明
三、使用环境
Ubuntu12,Pinos,Geany,C语言
四、实验过程与分析、调试过程
1、创建虚拟磁盘
在命令行输入pintos/src/userprog,进行make—>build,然后输入创建磁盘及对其进行分区的指令,初始化磁盘后复制,将可执行文件elf装入disk
pintos-mkdiskfilesys.dsk 2
pintos-f–q
pintos-p../../examples/echo-aecho---q
pintos-qrun'echox'
2.Pintos的用户程序处理中存在的问题
当系统需要执行一个文件时,就必须先对执行过程的需要的参数进行传递。
比如用哪种模式运行,需要用到的文件名称与路径是什么。
用一个数组来进行存储,并且把名字和参数分开处理。
传递参数时,把堆栈里的参数地址存放在一个新的数组里,以备后用。
然后执行字对齐,分别把参数地址、参数的个数、返回地址压栈。
系统调用是由系统提供的一组完成底层操作的函数集合,由用户程序通过中断调用,系统根据中断向量表和中断服务号确定函数调用,调用相应的函数完成相应的服务。
此外还有没有内部同步,并行的访问会互相影响,需要用到同步来保证同一时间只有一个进程能访问文件系统代码。
一个文件系统被用了多次后会产生大量外部碎片。
当操作系统准备运行某一个程序,而这个程序在磁盘上保存的程序代码被修改,则操作系统在运行是,可能会出现异常结果等问题
五、实验总结
对于这么大而复杂的工程,着实无从下手,难度太大,需要修改的文档和函数非常多基本都是借鉴参考,还是有大量问题没有解决,自己的代码编写能力必须加强,通过不断学习改进提高动手能力,争取以后自己完成项目
项目2文档
10122510325
修阳
1.需求分析(Pintos中存在的问题)
使得程序能够通过系统调用来与操作系统交互。
当用户程序想要用一些内核的功能时,需要用到系统调用。
现在只是实现了输出一段消息并且终止用户程序,需要更改代码来实现系统调用所需要的一切。
2.改进的思想及流程
a)进程终止消息
b)参数传递
c)系统调用
d)实现禁止对可执行文件进行读写
3.实现方法(代码及说明)
a)进程终止消息
int
process_wait(tid_tchild_tid)
{
structthread*t;
t=get_thread(child_tid);//t通过child_tid拿到子线程的所有信息
if(t==NULL||t->is_dead==true||t->is_waited==true)//如果t是空的,或者t是死亡了的,或者t在被它的父线程等待
return-1;//和原来一样,返回
sema_down(&t->sema);//改变t的信号量
t->is_waited=true;//t正在被它的父线程等待着
returnt->exit_status;//返回当前t的退出状态
}
//***************************ADDEND
void
process_exit(void)
{
structthread*cur=thread_current();
uint32_t*pd;
//***************************ADD
/*Semauptheparentthread.*/
printf("%s:
exit(%d)\n",thread_current()->name,thread_current()->exit_status);//打印当前线程的名字和退出状态
sema_up(&cur->sema);//修改当前线程的信号量
/*Destroythecurrentprocess'spagedirectoryandswitchback
tothekernel-onlypagedirectory.*/
pd=cur->pagedir;
if(pd!
=NULL)
{
/*Correctorderinghereiscrucial.Wemustset
cur->pagedirtoNULLbeforeswitchingpagedirectories,
sothatatimerinterruptcan'tswitchbacktothe
processpagedirectory.Wemustactivatethebasepage
directorybeforedestroyingtheprocess'spage
directory,orouractivepagedirectorywillbeone
that'sbeenfreed(andcleared).*/
cur->pagedir=NULL;
pagedir_activate(NULL);
pagedir_destroy(pd);
}
}
b)参数传递
/*Athreadfunctionthatloadsauserprocessandstartsit
running.*/
staticvoid
start_process(void*file_name_)
{
char*file_name=file_name_;
structintr_frameif_;
boolsuccess;
//***************************ADD
intn;//后面循环中会用到的,只是一个控制循环的参数。
char*token,*save_ptr;//*token指向参数*save_ptr指向指针
char*argv[50],**arg_addr_in_stack[50];
//分别定义了两个最大是50的数组,也就是说参数的个数最多是50个
intargc=0;//参数个数
//Splitupthefilename分解文件名
for(token=strtok_r(file_name_,"",&save_ptr);token!
=NULL;
token=strtok_r(NULL,"",&save_ptr))
//strtok_r()字符串解析,一直解析到token==NULL即最后一个
{
argv[argc]=token;//把解析出来的token赋给argv[]
argc++;
}
//***************************ADDEND
/*Initializeinterruptframeandloadexecutable.*/
memset(&if_,0,sizeofif_);
if_.gs=if_.fs=if_.es=if_.ds=if_.ss=SEL_UDSEG;
if_.cs=SEL_UCSEG;
if_.eflags=FLAG_IF|FLAG_MBS;
success=load(argv[0],&if_.eip,&if_.esp);
//***************************ADD
//passargument参数传递
//Ifloadsuccessed如果存储成功了的话
if(success)
{
//Pushargumentintostack把参数压入堆栈
n=argc-1;
//因为前面的for循环中在退出循环之前又执行了一次argc++
//减1表示argv[]的有效长度
while(n>=0)//从参数数组最后一个进行循环
{
if_.esp=if_.esp-strlen(argv[n])-1;//栈顶指针向前移动,里留出足够的空间给argv[n]
memcpy(if_.esp,argv[n],strlen(argv[n]));
//memcpy()字符串的拷贝。
//把argv[n]的值拷贝到if_.esp里,长度是strlen(argv[n])
arg_addr_in_stack[n]=(char**)if_.esp;
//把堆栈的位置赋值给参数地址
n--;
}
//Wordalign字对齐,四位一对齐
intoffset=(int)if_.esp%4;//先算出要多少个offset
if(offset!
=0)
{
if(offset<0)
offset=offset+4;//offset转换成正整数
if_.esp=if_.esp-offset;//栈顶指针向前移动offset位
}
//将参数传递到寄存器中,因为我们的地址是int类型的,而且地址是向下增长的,所以每次在内存中传地址的时候,我们的esp的指针必须每次向下移动4个字节,将argv中的内容根据argc的大小进行传递
//foranullargument
if_.esp=if_.esp-4;//栈顶指针向前移动,留一个位置给空参数
//Pushtheargumentaddressinstackintothestack参数地址入栈
n=argc-1;//根据前一个while循环可知,此时n=0。
//为了再一次进行压栈操作,所以要再赋一次值。
while(n>=0)
{
if_.esp=if_.esp-4;//栈顶指针向前移动四位
*(void**)if_.esp=(char**)arg_addr_in_stack[n];
//arg_addr_in_stack[n]=(char**)if_.esp;
//把之前赋给参数地址数组的值赋给现在的栈顶指针
//注意类型的不同
n--;//由后向前寻找参数地址
}
if_.esp=if_.esp-4;//栈顶指针向前移动出一个空位
*(void**)if_.esp=(char**)if_.esp+1;
//然后+1赋给*(void**)if_.esp
//Pushthenumberoftheargumentsintostack把参数个数压栈
if_.esp=if_.esp-4;//栈顶指针向前移动出一个空位
*(int*)if_.esp=argc;//把个数赋给*(int*)if_.esp
//Pushreturnaddressintostack.返回地址入栈
if_.esp=if_.esp-4;//栈顶指针向前移动出一个空位
*(void**)if_.esp=if_.esp;
//当前的返回地址赋给*(void**)if_.esp
}
//***************************ADDEND
/*Ifloadfailed,quit.*/
palloc_free_page(file_name);
if(!
success)
{
thread_current()->is_dead=true;
thread_current()->exit_status=-1;
thread_exit();
}
/*Starttheuserprocessbysimulatingareturnfroman
interrupt,implementedbyintr_exit(in
threads/intr-stubs.S).Becauseintr_exittakesallofits
argumentsonthestackintheformofa`structintr_frame',
wejustpointthestackpointer(%esp)toourstackframe
andjumptoit.*/
asmvolatile("movl%0,%%esp;jmpintr_exit":
:
"g"(&if_):
"memory");
NOT_REACHED();
}
c)系统调用
intwrite(intfd,constchar*buffer,unsignedintsize);
voidexit(intstatus);
voidhalt();
intexec(constchar*cmd_line);
intwait(intpid);
boolcreate(constchar*file,unsignedintinitial_size);
intopen(constchar*file);
intread(intfd,void*buffer,unsignedintsize);
intfilesize(intfd);
boolremove(constchar*file);
voidseek(intfd,unsignedintposition);
unsignedinttell(intfd);
voidclose(intfd);
添加的数据结构(共8个):
>>intexit_status//用于记录线程的退出状态
>>structsemaphoresema//线程的信号量
>>intnum_file_open//记录正在运行中的线程的数量
>>intopen_file[128]//用于记录线程所开启的文件的编号,这里因为是FAQ
>>//假定一个线程最多可以开启128个文件
>>tid_tparent_tid//用于记录当前线程的父线程的tid
>>boolis_waited//用一个布尔量记录当前线程是否正在被他的父线程等待中
>>boolis_dead//用于判别当前线程是否被杀死(beenkilled)
>>
>>该函数实现通过线程的tid可返回该线程:
>>structthread*get_thread(tid_ttid)
>>
>>该函数用于检查Thefunctiontotocheckwhetherthepointerisallright:
>>booladdr_is_right(void*addr)//用于检查该指针指向的地址是否合法
>>
>>structfile_fd//实现了文件的fd可以成功映射到该文件
>>{
>>intfd;//记录file的fd的值
>>structfile*fp;//记录指向文件的指针
>>structlist_elemelem;//用于list
>>};
>>用一个list来存储file_fd:
>>structlistfile_fd_list
以下是详细代码及分析:
#include"userprog/syscall.h"
#include"userprog/process.h"
#include"userprog/pagedir.h"
#include
#include
#include"threads/interrupt.h"
#include"threads/thread.h"
#include"threads/init.h"
#include"threads/vaddr.h"
#include"lib/kernel/stdio.h"
#include"filesys/filesys.h"
#include"filesys/file.h"
#include"devices/input.h"
staticvoidsyscall_handler(structintr_frame*);//用于控制整个系统调用过程
structfile_fd//实现了文件的fd可以成功映射到该文件
{
intfd;//记录file的fd的值
structfile*fp;//记录指向文件的指针
structlist_elemelem;//用于list
};
structlistfile_fd_list;//用来存储file_fd
intwrite(intfd,constchar*buffer,unsignedintsize);//向一个文件中写入
voidexit(intstatus);//终止当前process
voidhalt();//停止当前操作系统运行
intexec(constchar*cmd_line);//开始另一个process
intwait(intpid);//等待一个子进程的死亡
boolcreate(constchar*file,unsignedintinitial_size);
//创建一个file
intopen(constchar*file);//打开一个文件
intread(intfd,void*buffer,unsignedintsize);//从一个文件中读
intfilesize(intfd);//获取一个文件的大小
boolremove(constchar*file);//删除一个文件
voidseek(intfd,unsignedintposition);//改变在文件中的位置
unsignedinttell(intfd);//报告在文件中的当前位置
voidclose(intfd);//关闭文件
booladdr_is_right(void*addr);//检查地址是否合法
//系统调用初始化
void
syscall_init(void)
{
intr_register_int(0x30,3,INTR_ON,syscall_handler,"syscall");
list_init(&file_fd_list);
}
//该函数查看当前是哪一个syscall,然后调用相应的系统调用函数
staticvoid
syscall_handler(structintr_frame*fUNUSED)//读取出中断帧
{//系统调用可能会从用户内存中读取或写入函数,
//所以在每调用一个函数之前都要先检验堆栈顶指针指向的
//地址值是否合法。
if(!
addr_is_right(f->esp))//指向栈顶的指针
exit(-1);//如果不合法则调用exit()函数来退出。
intsyscall=*(int*)(f->esp);
//如果地址合法才进行执行系统调用。
if(syscall==SYS_WRITE)
//根据用户不同的调用号,进行不同的系统调用。
{
if(addr_is_right(f->esp+4)&&addr_is_right(f->esp+8)&&addr_is_right(f->esp+12))
//检查这三个地址空间值是否合法
{
intfd=*(int*)(f->esp+4);
constchar*buffer=(char*)*(unsignedint*)(f->esp+8);
unsignedintsize=*(unsignedint*)(f->esp+12);
f->eax=write(fd,buffer,size);
}
else
exit(-1);
}
if(syscall==SYS_EXIT)
{
if(addr_is_right(f->esp+4))
{
intstatus=*(int*)(f->esp+4);
exit(status);
}
else
exit(-1);
}
if(syscall==SYS_HALT)
halt();
if(syscall==SYS_EXEC)
{
if(addr_is_right(f->esp+4))
{
constchar*cmd_line=(char*)*(unsignedint*)(f->esp+4);
f->eax=exec(cmd_line);
}
else
exit(-1);
}
if(syscall==SYS_WAIT)
{
if(addr_is_right(f->esp+4))
{
intpid=*(int*)(f->esp+4);
f->eax=wait(pid);
}
else
exit(-1);
}
if(syscall==SYS_CREATE)
{
if(addr_is_right(f->esp+4)&&addr_is_right(f->esp+8))
{
constchar*file=(char*)*(unsignedint*)(f->esp+4);
unsignedintsize=*(unsignedint*)(f->esp+8);
f->eax=create(file,size);
}
else
exit(-1)