上机实践报告Project2.docx

上传人:b****7 文档编号:23598011 上传时间:2023-05-18 格式:DOCX 页数:31 大小:30.36KB
下载 相关 举报
上机实践报告Project2.docx_第1页
第1页 / 共31页
上机实践报告Project2.docx_第2页
第2页 / 共31页
上机实践报告Project2.docx_第3页
第3页 / 共31页
上机实践报告Project2.docx_第4页
第4页 / 共31页
上机实践报告Project2.docx_第5页
第5页 / 共31页
点击查看更多>>
下载资源
资源描述

上机实践报告Project2.docx

《上机实践报告Project2.docx》由会员分享,可在线阅读,更多相关《上机实践报告Project2.docx(31页珍藏版)》请在冰豆网上搜索。

上机实践报告Project2.docx

上机实践报告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)

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1