pintos-pro2-project 2-User Program 下载本文

Pintos project2

作者:西安电子科技大学

这个项目将使pintos可以加载并执行用户程序,并且为用户程序提供系统调用。

Project2 需要完成的的任务有四个:

? Task1 Process Termination Messages进程终止信息 ? Task2 Argument Passing 参数传递 ? Task3 System Calls 系统调用

? Task4 Denying Writes to Executables不能写入可执行文件

Task1: Process Termination Messages进程终止信息

要求:

1.在进程结束时输出退出代码(就是main函数的返回值,或者异常退出代码。

注意: 用户进程结束时输入退出代码,核心线程返回时不输入。 输出格式被规定如下:

? printf (“%s: exit(%d)\\n”,..); 实现方法:

1. 既然要打印返回值,就得用一个变量保存返回值,于是在struct thread 结构中加入一个变量回保存返回值: int ret;

在init_thread()函数中初始化为0(这里可以不用初始化)。 2. 在线程退出里要保存其返回值到ret中,这个将在系统调用里的exit函数中保存,这里先不考虑。 在什么地方加入printf()呢?

每个线程结束后,都要调用thread_exit()函数,如果是加载了用户进程,在thread_exit()函数中还会调用process_exit()函数, 在process_exit()函数中,如果是用户进程,那么其页表一定不为NULL,而核心进程页表一定为NULL,即只有用户进程退出时if(pd!=NULL){ }就会成立,所以在大括号中加入:

printf (“%s: exit(%d)\\n”,cur->name,cur->ret); 其中cur=thread_current();即当前线程的struct thread 指针。 TASK1 OK…

TASK2 Argument Passing 参数传递

要求:

1. 分离从命令行传入的文件名和各个参数。 2. 按照C函数调用约定,把参数放入栈中。 实现方法:

1.分离参数的方法:用string.h中的strtok_r()函数,在string.c中有详细的说明。

2.在process_execute()函数中,因为thread_create()需要一个线程名,此时应该传递给它文件名(不带参数)。可如下处理: char *real_name, *save_ptr;

real_name = strtok_r (file_name, \

tid = thread_create (real_name, PRI_DEFAULT, start_process, fn_copy);

(3)在start_process()函数中,再次分离参数,放入栈中。 由于在process_execute()对file_name作了复制,文件名并未丢失,但是要注意,无论加载用户程序成功还是失败,都得释放file_name所占用的一个页的空间(Debug here 3 weeks)。 注意:传给Load()函数的参数也只能有文件名,所以在load()函数前要分离出文件名: char *token=NULL, *save_ptr=NULL;

token = strtok_r (file_name, \success = load (token, &if_.eip, &if_.esp); 参数放置的一种方法: (1)找到用户栈指针:

在start_process()函数中有struct intr_frame if_; 这样一个结构,其中有一个成员if_.esp,这就是用户栈指针,在load()函数

中为其赋值,分配了栈空间。

(2)调用strtok_r 分离出一个个参数(就是一个个字符串了),把每个字符串都复制到用户栈中,并把他在栈中的位置记录到一个数组中,以备下一步使用。注意:栈是向下增长,而字符串是向上增长。 char *esp=(char *)if_.esp;

char *arg[256]; //assume numbers of argument below 256 int i,n=0;

for (; token != NULL;token = strtok_r (NULL, \ {

esp-=strlen(token)+1; //because user stack increase to low addr. strlcpy(esp,token,strlen(token)+2); //copy param to user stack arg[n++]=esp; }

(3)要加入一个双字的对齐,因为是32位的,所以就是四字节对齐。

while((int)esp%4make) //word align

esp--; //注意:栈是向下增长,所以这里是—而不是++;

(4)要将第(2)步保存下的指针逆序放入栈中。

按照C约定,先要放入一个0,以防没有参数。

int *p=esp-4; *p--=0;

然后依次放入参数n的地址,参数n-1的地址 … 参数0的地址。

for(i=n-1;i>=0;i--) //place the arguments' pointers to stack *p--=(int *)arg[i];

(5)放入argc,argv

*p--=p+1; *p--=n; *p--=0; esp=p+1;

(6)让用户栈指针指向新的栈顶

if_.esp=esp

如下图摆放。 如果命令行是: /bin/ls –l foo bar

完整代码见附录!

TASK 3 system call 系统调用

要求:

(1)实现以下系统调用:

? pfn[SYS_WRITE]=IWrite; //printf和写文件需要。 ? pfn[SYS_EXIT]=IExit; //退出时return后调用 ? pfn[SYS_CREATE]=ICreate; //创建文件 ? pfn[SYS_OPEN]=IOpen; //打开文件 ? pfn[SYS_CLOSE]=IClose; //关闭文件 ? pfn[SYS_READ]=IRead; // 读文件 ? pfn[SYS_FILESIZE]=IFileSize; //返回文件大小