BUAA_OS_lab6

BUAA_OS_lab6学习日记

Thinking

Thinking 6.1

示例代码中,父进程操作管道的写端,子进程操作管道的读端。如果现在想 让父进程作为“读者”,代码应当如何修改?

父进程更改写端1,子进程更改读端0。

Thinking 6.2

上面这种不同步修改 pp_ref 而导致的进程竞争问题在 user/lib/fd.c 中 的dup 函数中也存在。请结合代码模仿上述情景,分析一下我们的 dup函数中为什么会出 现预想之外的情况

两个相关的页面map或者unmap的之间发生了时钟中断,会导致不一致的现象。

Thinking 6.3

阅读上述材料并思考:为什么系统调用一定是原子操作呢?如果你觉得不是 所有的系统调用都是原子操作,请给出反例。希望能结合相关代码进行分析说明。

系统调用一定是原子操作,进程切换是通过定时器产生时钟中断,触发时钟中断切换进程。但是syscall跳转到内核态时,CPU将SR寄存其的IE位置0,关闭了时钟中断。

Thinking 6.4

仔细阅读上面这段话,并思考下列问题

  • 按照上述说法控制 pipe_close中 fd和 pipeunmap的顺序,是否可以解决上述场 景的进程竞争问题?给出你的分析过程。
  • 我们只分析了 close时的情形,在 fd.c中有一个 dup函数,用于复制文件描述符。 试想,如果要复制的文件描述符指向一个管道,那么是否会出现与 close类似的问 题?请模仿上述材料写写你的理解

当对于pipe页面的引用次数小于对两个fd的和的时候,就会出现安全问题,而只要先解除fd再解除pipe,就不会出现上述问题,问题也仅仅只是拉大了二者的差距而已,对于结果没有影响。

会出现pipe页面的引用次数小于对两个fd的和的问题

Thinking 6.5

  • 认真回看Lab5文件系统相关代码,弄清打开文件的过程。
  • 回顾Lab1与Lab3,思考如何读取并加载ELF文件。
  • 在Lab1 中我们介绍了 data text bss 段及它们的含义,data 段存放初始化过的全 局变量,bss段存放未初始化的全局变量。关于memsize和filesize,我们在Note 1.3.4中也解释了它们的含义与特点。关于Note1.3.4,注意其中关于“bss段并不在文 件中占数据”表述的含义。回顾Lab3并思考:elf_load_seg()和load_icode_mapper() 函数是如何确保加载ELF文件时,bss段数据被正确加载进虚拟内存空间。bss段 在ELF中并不占空间,但ELF加载进内存后,bss段的数据占据了空间,并且初始 值都是0。请回顾elf_load_seg() 和 load_icode_mapper() 的实现,思考这一点 是如何实现的?

下面给出一些对于上述问题的提示,以便大家更好地把握加载内核进程和加载用户进程的 区别与联系,类比完成 spawn函数。

关于第一个问题,在Lab3中我们创建进程,并且通过 ENV_CREATE(…) 在内核态加 载了初始进程,而我们的 spawn函数则是通过和文件系统交互,取得文件描述块,进而找 到ELF 在“硬盘”中的位置,进而读取。 关于第二个问题,各位已经在Lab3中填写了load_icode 函数,实现了ELF 可执行 文件中读取数据并加载到内存空间,其中通过调用elf_load_seg 函数来加载各个程序段。 在Lab3 中我们要填写 load_icode_mapper 回调函数,在内核态下加载 ELF 数据到内存 空间;相应地,在Lab6中spawn函数也需要在用户态下使用系统调用为ELF数据分配空 间。

  • 在 Lab3 中我们创建进程,并且通过 ENV_CREATE(…) 在内核态加载了初始进程,而我们的 spawn 函数则是通过和文件系统交互,取得文件描述块,进而找到 ELF 在“硬盘”中的位置,进而读取。
  • 在 Lab3 中填写的 load_icode 函数,实现了 ELF 可执行文件中读取数据并加载到内存空间,其中通过调用 elf_load_seg 函数来加载各个程序段。在 Lab3 中我们要填写 load_icode_mapper 回调函数,在内核态下加载 ELF 数据到内存空间;相应地,在 Lab6 中 spawn 函数也需要在用户态下使用系统调用为 ELF 数据分配空间。
  • bss段应该与text段data段连续的放在一起,但是ELF中没有空间,在分配映射页面时,text段与data段没有占满的空间置为0给了bss段,然后再给他另外分配的时候,只使用syscall_mem_alloc而不映射

Thinking 6.6

通过阅读代码空白段的注释我们知道,将标准输入或输出定向到文件,需要 我们将其dup到0或1号文件描述符(fd)。那么问题来了:在哪步,0和1被“安排”为 标准输入和标准输出?请分析代码执行流程,给出答案

在user/init.c中

1
2
3
4
5
6
7
if ((r = opencons()) != 0) {
user_panic("opencons: %d", r);
}
// stdout
if ((r = dup(0, 1)) < 0) {
user_panic("dup: %d", r);
}

Thinking 6.7

在 shell 中执行的命令分为内置命令和外部命令。在执行内置命令时shell不 需要fork 一个子 shell,如 Linux 系统中的 cd 命令。在执行外部命令时 shell 需要 fork 一个子shell,然后子 shell 去执行这条命令。 据此判断,在MOS 中我们用到的 shell 命令是内置命令还是外部命令?请思考为什么 Linux 的 cd 命令是内部命令而不是外部命令?

  • 外部命令
  • 内部命令

Thinking 6.8

在你的 shell 中输入命令 ls.b | cat.b > motd。

  • 请问你可以在你的shell 中观察到几次spawn?分别对应哪个进程?
  • 请问你可以在你的shell 中观察到几次进程销毁?分别对应哪个进程?

答案:

  • 有两次spawn,分别打开了ls.b,cat.b进程
  • 有四个进程的销毁,分别是左指令的执行进程,右指令的执行进程,spawn打开的两个执行进程。

实验感想和总结

lab6 总体的实验难度不难,函数也比较少,但是可以说是和我们日常最贴近的一次lab,通过实验,我们实现了shell的一些简单功能。


BUAA_OS_lab6
https://fantasylee21.github.io/2024/05/29/BUAA-OS-lab6/
作者
Fantasylee
发布于
2024年5月29日
更新于
2024年6月11日
许可协议