Stanford cs140 Pintos Project2实验目标

0. 前言

本实验出自斯坦福大学cs140课程,实验环境为Pintos+Bochs,鉴于其文档为全英文,故为了方便读者及自己尝试,整理翻译了其中实验2的主要任务。也加入了自己的理解,方便读者理解实验内容。

1. 进程终结信息

每当一个用户进程因为该进程调用exit或其它原因而结束时,需要打印该进程的进程名和退出码(exit code)。输出格式为:

printf ("%s: exit(%d)\n", ...);

打印的进程名应当是要作为参数传递给process_execute函数的完整名字(省略命令行参数),当不是用户进程的内核线程终止或调用系统调用时,请勿打印这些消息。当一个进程没有成功加载时,这个消息是可选的(不一定需要打印)。

2. 参数传递

暂时(未改动之前),process_execute函数不支持传递参数给一个新的进程,因为process_execute函数的参数仅仅只有一个文件名而已。所以,需要拓展process_execute函数的功能来实现这一点。我们要把它这唯一一个参数用空格分隔开来实现上述功能。分隔后的第一个单词是文件名,第二个单词是第一个参数,以此类推。比如:process_execute("grep foo bar")应该会执行grep线程,并传递两个参数foobar

在命令行中,多个空格的效果和一个空格是一样的。你可以对命令行参数的长度加以合理的限制。比如:你可以限制它的长度在一页的范围里(4kB)。

我们可以通过任何方式来实现参数分离。推荐的方法是在“lib/string.h”中定义的strtok_r()函数,该函数在"lib/string.c"里有注释可以参阅。

3. 系统调用

系统调用说明


在“userprog/syscall.c”里实现系统调用,具体来说,是通过其中的syscall_handler函数。系统通过传递来的intr_frame *类型的参数f (其实是f->esp,也就是系统调用参数)来识别系统调用的类型并执行相应的操作。

要实现的系统调用一共有以下13个。这些系统调用的原型都在“lib/user/syscall.h”里。系统调用号在“lib/syscall-nr.h”里。

  • void halt(void)

    通过调用shutdown_power_off()来让Pintos关机。

  • void exit(int status)

    结束当前的用户程序,并返回状态给内核kernel,如果当前进程的父进程正在等待该进程,则这个状态就是应该返回的状态。传统来说,状态0代表返回成功而一个非0值代表有错误。

  • pid_t exec(const char * cmd_line)

    cmd_line会传入进程名及其他参数,exec会去执行该进程,并返回新进程的id(pid)。如果这个进程无法加载或运行(无论什么原因),那么就返回-1. 因此,直到父进程判断完子进程是否加载好了可执行文件之前,父进程无法从exec返回。我们必须通过同步操作来保证这一点。

    我们可以调用process_execute()函数并在它之中完成这些修改。

  • int wait(pid_t pid)

    等待子进程pid并检查该子进程的退出状态(exit status)。

    如果pid子进程仍然未被kill,那么就一直等待它直到它进入终结态。然后,返回pid传递给exit的状态值。如果pid进程没有调用exit,而是被kernel内核终结(比如因为一个exception而被kill),那么wait(pid)必须返回-1.

    如果下列情况中有任何一个为true时,wait会失败并返回-1:

    1. pid不是该进程的直接子进程。(pid是子进程当且仅当该进程能够收到pid作为成功调用exec的返回值)。注意:子进程不能继承。A有一个子进程为B,B有一个子进程为C,此时C不是A的直接子进程。A调用wait(C)将失败。相似地,在子进程的父进程exit之前,子进程也不能被重新分配一个父进程。
    2. 该进程已经调用了wait(pid),即已经在等待pid了。

    一个进程可能会产生任意数量的子进程,并以任意的顺序等待它们,甚至会不等待它们的子进程返回就exit。我们要考虑所有wait可能的情况。注意:无论父进程是否等待某个子进程也无论该子进程是否在它的父进程之前或之后exit,该子进程的资源,包括它的线程结构(struct thread)都必须释放。

    我们可以调用process_wait()函数并在它之中完成这些修改。

    斯坦福官方网站提示:Implementing this system call requires considerably more work than any of the rest.

    完成该系统调用花费的精力比其它任何系统调用都要多。


  • bool create(const char *file,unsigned initial_size)

    创建一个叫file的新文件,初始大小为initial_size. 创建成功则返回true,否则返回false。注意:此时不需要打开该文件。

  • bool remove(const char *file)

    删除叫file的文件。删除成功则返回true,否则返回false。一个文件无论其处在打开或者关闭状态,都可能被删除。

  • int open(const char *file)

    打开叫file的文件。打开成功则返回一个非负整数(文件标识符fd),否则返回-1.

    文件标识符中,0和1是默认的:0是标准输入,1是标准输出。系统调用不会返回这两个文件标识符。

    每个进程都有独立的文件标识符,文件标识符不会被子进程继承。

    当一个文件被重复打开了多次,不管它是被同一个或者不同的进程打开的,每一个open都要返回一个新的文件标识符。在删除文件时,同一个文件的不同文件标识符是独立的。他们不会共享内存中的位置。(比如,一个文件以文件标识符2和3打开了,删除标识符为2的文件不会删除标识符为3的文件)。

  • int filesize(int fd)

    返回以fd打开的文件的大小(以byte为单位)。

  • int read(int fd, void *buffer,unsigned size)

    读文件时,往buffer里读入打开的文件fdsize大小的数据。返回实际读入的bytes数量(在文件结尾时则返回0),若读入失败则返回-1.

    读键盘输入时,标识符为0的文件(标准输入)通过input_getc()read键盘输入。

  • int write(int fd, const void *buffer,unsigned size)

    写文件时,往buffer里写入打开的文件fdsize大小的数据。返回实际写入的bytes数量。有些情况下(一些bytes无法写入),这个数量可能比size小。

    在文件末尾写入通常会扩展文件,但是基本的文件系统无法实现文件增长。预期的行为是在文件末尾写入尽可能多的字节并返回实际写入的数量,如果根本无法写入任何字节,则返回0.

    写入console输出时,我们的代码应该在一次调用putbuf()的过程中写入所有的buffer,只要合理地控制大小即可。不然,不同进程的输出会交替出现。

  • void seek(int fd, unsigned position)

    把下一个要读入或写入的字节跳转到已打开文件fdposition位置。(position为0时代表文件开头)

    在文件的当前末尾进行seek不是错误。以后的read将获得0字节,表示文件结束。以后的write将扩展文件,并用零填充所有未写入的间隙。(但是,在Pintos中,文件在项目4完成之前具有固定的长度,因此文件末尾的写入将返回错误。)

  • unsigned tell(int fd)

    返回下一个在已打开文件fd中即将被读入或写入的字节的位置。

  • void close(int fd)

    关闭文件fd。退出或终结一个进程需要关闭所有其文件标识符,就像是对每一个fd都调用了close一样。


要实现系统调用,我们需要提供在用户虚拟地址空间中读取和写入数据的方法。在获得系统调用编号之前,我们就需要此功能,因为系统调用编号位于用户的虚拟地址空间中的用户堆栈上。这可能有点棘手:如果用户提供了无效的指针,指向内核内存的指针或部分位于这些区域之一的块,该怎么办?答案是应该通过终止用户进程来处理这些情况。


我们还必须同步系统调用,以便任意数量的用户进程可以同步进行调用。一次从多个线程调用“filesys”目录中提供的文件系统代码是不安全的 。目前最好不要修改该目录中的代码。


还有一点很重要:用户程序无法执行的任何操作都不应该会导致OS崩溃,死机,断言失败或其他故障。测试将尝试以多种方式中断我们的系统调用。所以需要考虑所有极端情况并加以处理。用户程序应该能够导致OS停止的唯一方法是调用halt系统调用。

4. 拒绝写入数据至可执行文件

我们要添加代码,来拒绝写入数据至用作可执行文件的文件。我们可以调用file_deny_write()来禁止写入,调用file_allow_write()来恢复写入权限。注意:关闭一个文件也会让它恢复写入权限,所以如果我们要禁止写入,我们必须让该文件保持open状态,直到进程结束运行。

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值