上机实践报告Project2Word文档下载推荐.docx
- 文档编号:17338949
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:26
- 大小:27.26KB
上机实践报告Project2Word文档下载推荐.docx
《上机实践报告Project2Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《上机实践报告Project2Word文档下载推荐.docx(26页珍藏版)》请在冰豆网上搜索。
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.实现方法(代码及说明)
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->
//修改当前线程的信号量
/*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).*/
pagedir=NULL;
pagedir_activate(NULL);
pagedir_destroy(pd);
}
b)参数传递
<
process.c>
/*Athreadfunctionthatloadsauserprocessandstartsit
running.*/
staticvoid
start_process(void*file_name_)
char*file_name=file_name_;
structintr_frameif_;
boolsuccess;
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++;
/*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);
//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参数地址入栈
//根据前一个while循环可知,此时n=0。
//为了再一次进行压栈操作,所以要再赋一次值。
=0)
if_.esp=if_.esp-4;
//栈顶指针向前移动四位
*(void**)if_.esp=(char**)arg_addr_in_stack[n];
//arg_addr_in_stack[n]=(char**)if_.esp;
//把之前赋给参数地址数组的值赋给现在的栈顶指针
//注意类型的不同
//由后向前寻找参数地址
//栈顶指针向前移动出一个空位
*(void**)if_.esp=(char**)if_.esp+1;
//然后+1赋给*(void**)if_.esp
//Pushthenumberoftheargumentsintostack把参数个数压栈
*(int*)if_.esp=argc;
//把个数赋给*(int*)if_.esp
//Pushreturnaddressintostack.返回地址入栈
*(void**)if_.esp=if_.esp;
//当前的返回地址赋给*(void**)if_.esp
/*Ifloadfailed,quit.*/
palloc_free_page(file_name);
if(!
success)
thread_current()->
is_dead=true;
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();
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"
userprog/process.h"
userprog/pagedir.h"
#include<
stdio.h>
syscall-nr.h>
threads/interrupt.h"
threads/thread.h"
threads/init.h"
threads/vaddr.h"
lib/kernel/stdio.h"
filesys/filesys.h"
filesys/file.h"
devices/input.h"
staticvoidsyscall_handler(structintr_frame*);
//用于控制整个系统调用过程
structlistfile_fd_list;
//用来存储file_fd
//向一个文件中写入
//终止当前process
//停止当前操作系统运行
//开始另一个process
//等待一个子进程的死亡
//创建一个file
//打开一个文件
//从一个文件中读
//获取一个文件的大小
//删除一个文件
//改变在文件中的位置
//报告在文件中的当前位置
//关闭文件
booladdr_is_right(void*addr);
//检查地址是否合法
//系统调用初始化
syscall_init(void)
intr_register_int(0x30,3,INTR_ON,syscall_handler,"
syscall"
list_init(&
file_fd_list);
//该函数查看当前是哪一个syscall,然后调用相应的系统调用函数
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)&
&
esp+8)&
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)
esp+4))
intstatus=*(int*)(f->
exit(status);
exit(-1);
if(syscall==SYS_HALT)
halt();
if(syscall==SYS_EXEC)
constchar*cmd_line=(char*)*(unsignedint*)(f->
eax=exec(cmd_line);
if(syscall==SYS_WAIT)
intpid=*(int*)(f->
eax=wait(pid);
if(syscall==SYS_CREATE)
esp+8))
constchar*file=(char*)*(unsignedint*)(f->
eax=create(file,size);
exit(-1)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 上机 实践 报告 Project2