BUAA_OS lab6实验报告
一、思考题
1. 思考6.1
示例代码中,父进程操作管道的写端,子进程操作管道的读端。如果现在想让父进程作为“读者”,代码应当如何修改?
修改后代码如下(交换case 0 和default部分的代码):
2. 思考6.2
上面这种不同步修改 pp_ref 而导致的进程竞争问题在 user/fd.c 中的dup 函数中也存在。请结合代码模仿上述情景,分析一下我们的 dup 函数中为什么会出现预想之外的情况?
考虑这样的伪代码:
if(fork() == 0) {
dup(p[1]);
read(p[0]);
}
else {
dup(p[0]);
write(p[1]);
}
注意到在dup函数中,先对fd执行syscall_mem_map,后对data执行syscall_mem_map。
子进程先开始执行,执行到dup和read之间时发生时钟中断,此时pageref(p[1]) == 1,pageref(pipe) == 1;父进程开始执行,在dup函数中执行到fd的map之后,data的map之前,此时pageref(p[0]) == 1,pageref(pipe) == 1;时钟中断,子进程再次开始执行,此时执行read函数,判断发现pageref(p[0]) == pageref(pipe),误认为是写者全部结束,于是错误地返回了。
3. 思考6.3
阅读上述材料并思考:为什么系统调用一定是原子操作呢?如果你觉得不是所有的系统调用都是原子操作,请给出反例。希望能结合相关代码进行分析。
系统调用一定是原子操作,因为在通过系统调用陷入内核态时汇编代码关闭了时钟中断。
4. 思考6.4
仔细阅读上面这段话,并思考下列问题
• 按照上述说法控制 pipeclose 中 fd 和 pipe unmap 的顺序,是否可以解决上述场景的进程竞争问题?给出你的分析过程。
• 我们只分析了 close 时的情形,在 fd.c 中有一个 dup 函数,用于复制文件内容。试想,如果要复制的是一个管道,那么是否会出现与 close 类似的问题?请模仿上述材料写写你的理解。
-
可以解决。最初pageref(p[0]) = 2,pageref(p[1]) = 2,pageref(pipe) = 4;仍考虑子进程先运行,对p[1]执行close函数时先解除了对写端fd的映射,之后发生时钟中断,此时pageref(p[0]) = 2,pageref(p[1]) = 1,pageref(pipe) = 4;父进程执行完close(p[0])后,pageref(p[0]) = 1,pageref(p[1]) = 1,pageref(pipe) = 3,父进程开始运行时仍不满足写端关闭的条件,因此竞争问题没有出现。
-
在程序执行时,总满足pageref(p[0]) ≤ pageref(pipe),如果在dep中先对fd进行映射,此时fd的rep先增加,可能填补了二者的空隙,造成读端已满的假象(写端同理),因此也会出现与close相似的问题,需要调整映射的顺序。
5. 思考6.5
bss 在 ELF 中并不占空间,但 ELF 加载进内存后,bss 段的数据占据了空间,并且初始值都是 0。请回答你设计的函数是如何实现上面这点的?
与lab3实现几乎完全相同,当系统调用执行sys_mem_alloc函数时进一步调用了page_alloc函数,其中有bzero使新分配的页面内容全部为0,只要不向数据段错误地复制内容,即可保证该段初始值为0。
6. 思考6.6
为什么我们的 *.b 的 text 段偏移值都是一样的,为固定值?
观察user/user.lds文件内容,有如下代码:
. = 0x00400000;
_text = .; /* Text and read-only data */
.text : {
*(.text)
*(.fixup)
*(.gnu.warning)
}
这说明所有文件在链接时都以此规定相同的起始地址。
7.思考6.7
在哪步,0和1被“安排”为标准输入和标准输出?请分析代码执行流程,给出答案。
在user/init.c中,有如下代码,在此处将0和1安排为了标准输入输出:
close(0);
if ((r = opencons()) < 0)
user_panic("opencons: %e", r);
if (r != 0)
user_panic("first opencons used fd %d", r);
if ((r = dup(0, 1)) < 0)
user_panic("dup: %d", r);
二、实验难点
1. 管道与进程切换
由于时钟中断可能在函数执行中间发生,而有时需要保证同步性,因此需要注意判断是否在同一时间片内。_pipeisclosed函数中就需要运用env_runs变量计数进程执行次数,只有在同一次数内才能保证pageref的同步性。
2. spawn
三、体会与感想
本次lab用时13小时,相比于前几个lab用时少了很多,也可能是因为到了考期,而且没有了课上测试的要求,有些代码没有很认真地理解,做得有些潦草。计划考期结束后重新过一遍,加深对管道的理解。
实现完文件系统和管道后,操作系统似乎更加有意思了起来,原来只是对着一块黑黑的屏幕写一些十分抽象的代码,运行结果也只是一些printf的输出,而现在可以自己创建文件,可以实现控制台中断,与控制台交互等,随便敲敲都会有显示,于是像个没见过世面的小孩子,觉得惊喜又有趣。
四、残留难点
对填写范围以外的官方代码理解还不透彻,需要更细致的学习。