lab6实验报告

lab6实验报告

一、实验思考题

Thinking6.1

1 #include <stdlib.h>
2 #include <unistd.h>
3
4 int fildes[2];
5 /* buf size is 100 */
6 char buf[100];
7 int status;
8
9 int main(){
10
11 status = pipe(fildes);
12
13 if (status == -1 ) {
14 /* an error occurred */
15	 printf("error\n");
16 }
17
18
19 switch (fork()) {
20 	case -1: /* Handle error */
21 	break;
22
23
24 	case 0: /* Child - reads from pipe */
25 	close(fildes[1]); /* Write end is unused */
26 	read(fildes[0], buf, 100); /* Get data from pipe */
27 	printf("child-process read:%s",buf); /* Print the data */
28 	close(fildes[0]); /* Finished with pipe */
29 	exit(EXIT_SUCCESS);
30
31
32 	default: /* Parent - writes to pipe */
33 	close(fildes[0]); /* Read end is unused */
34 	write(fildes[1], "Hello world\n", 12); /* Write data on pipe */
35 	close(fildes[1]); /* Child will see EOF */
36 	exit(EXIT_SUCCESS);
37 	}
38 }

示例代码中case 0段与default段分别是子进程和父进程,子进程读,父进程写。如果想让父进程作为“读者”,可以交换case 0default的语句块。

Thinking6.2

一种可能的情况是,父子进程如果出现

  • 父进程已经关闭管道p[0],准备执行ispipeclosed(p[1])函数。
  • 子进程执行dup(p[1]),在刚刚完成dupfd,但还没有进入dupPipe结构体部分。

p[1]reference次数为3,p[0]reference为1,Pipe结构体所在页面映射在父进程p[0]和子进程的p[0]p[1]fdData部分,reference次数同样为3。

这时在父进程的ispipeclosed(p[1])进行判断pageref(wfd) == pageref(pipe)将会判断为真。

Thinking6.3

用户在调用syscall后,操作系统不应该允许其他程序执行,直到调用完毕返回。

系统调用进入时,操作系统会执行关中断指令。这在syscall.SCLI中体现。所以此时系统调用并不能被打断。相关的sys_ipc_recv可以理解为设置进程的相关状态,进入recv状态,这一个操作也是原子操作,不能被打断。

Thinking6.4

可以解决竞争。当ref_a > ref_b,如果先减少ref_a再减少ref_b可能会造成中间有短暂的ref_a == ref_b的环节,但是改变顺序之后先ref_b减少所以不会出现中间有相等的过程,可以解决该问题。

dup是个增加的过程,所以为了避免出现相等的中间过程时被竞争,应该先让大的一个增加,再增加小的。

// ref_a > ref_b
ref_a++;
ref_b++;

Thinking6.5

.bss段在加载过程中,会根据其中的memsz属性分配内存空间,并进行清零的操作。

Thinking6.6

在链接部分user.lds中规定了.text段首先被链接,而后面的有可能受到前面段大小的影响,但.text段的偏移是固定的。

. = 0x00400000;

_text = .;
.text : {
    	*(.text)
        *(.fixup)
        *(.gnu.warning)
}

Thinking6.7

在初始化中,init.cdup(0, 1)

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);

二、实验难点图示

首先是对于整个流程的理解,以及关于前面lab的隐藏bug。由于之前页面映射机制的bug,导致后续实现时总是在15到20分之间波动。没写spawn是20,写了却变成15,一度难以定位bug

spawn

  • 文件系统
  • 进程
  • 页面映射
  • 初始化
  • 执行

文件系统部分通过调用open相关内容打开对应的文件。然后利用syscall_env_alloc创建子进程。接着将目标程序加载到子进程的地址空间中,分配相关的物理页面。之后进行栈、堆等空间的初始化工作,并设置相关的参数。最后标记为子进程可执行。

pipe竞争问题

需要有并发的思想。

三、体会与感想

本次实验花费大量时间在bug的定位上,因为一个小疏忽在这里浪费了很多时间,不过还是很高兴最后能够找到。spawn函数的设计和管道pipe之间并发存在的竞争相对来说是个难点。os的课下lab已经全部结束,回顾整个lab确实能让自己的能力提高不少,不同于oo的巨大工程需要手写几千行代码,os关于工程的阅读能力有很大的锻炼,需要理解整个操作系统如何运作。最后还要感谢一路以来老师、助教、同学的陪伴!

posted @ 2023-03-14 16:34  Jareth  阅读(96)  评论(0)    收藏  举报