Post

BUAA-OS-lab6

BUAA-OS-lab6

lab6 实验报告

思考题

Thinking 6.1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
switch (fork()) {
    case -1:
        break;
    
    case 0: /* 子进程 - 作为管道的写者 */
        close(fildes[0]); /* 关闭不用的读端 */
        write(fildes[1], "Hello world\n", 12); /* 向管道中写数据 */
        close(fildes[1]); /* 写入结束,关闭写端 */
        exit(EXIT_SUCCESS);
    
    default: /* 父进程 - 作为管道的写者 */
        close(fildes[1]); /* 关闭不用的写端 */
        read(fildes[0], buf, 100); /* 从管道中读数据 */
        printf("father-process read:%s",buf); /* 打印读到的数据 */
        close(fildes[0]); /* 读取结束,关闭读端 */
        exit(EXIT_SUCCESS);
}

Thinking 6.2

此前的 dup 函数先映射文件描述符,再映射文件内容,如果在映射完文件描述符后,进程被中断,那么另一程序会错误的认为文件映射已经完成,产生错误。

Thinking 6.3

.macro CLI
        mfc0    t0, CP0_STATUS
        li      t1, (STATUS_CU0 | 0x1)
        or      t0, t1
        xor     t0, 0x1
        mtc0    t0, CP0_STATUS
.endm

根据这一段代码可以看出,操作系统在系统调用后会屏蔽中断,因此系统调用期间不会被中断,是原子操作。

Thinking 6.4

  • 可以解决。先关闭缓冲区,缓冲区的引用次数被修改,此时即使发生中断,pipe 也会阻止读写操作。
  • 可以解决。先建立缓冲区,此时 pipe 已经可以进行正常的读写过程了。

Thinking 6.5

  • user/lib/files.c 文件中的 open 在最顶层被用户调用,这个函数又调用 fsips,向文件系统进程发送请求,并等待返回接受的消息,文件系统进程的 serve 函数调用 file_open 完成文件的打开操作,并返回返回值。

  • ELF文件中的段信息是通过 Elf32_Phdr 结构体数组来描述的,其中包含了各个段的类型、在文件中的偏移、在内存中的虚拟地址、大小等信息。对于 bss 段,虽然它在文件中不占据实际存储空间,但它在内存中有一个预期的大小,用于存放未初始化的全局变量和静态变量,这些变量默认值为0。

    当加载器遍历ELF文件的各个段并调用 elf_load_seg() 处理每个段时,关键在于如何处理 sgsize(即段在内存中的总大小,对应 p_memsz)与 bin_size(段在文件中的大小,对应 p_filesz)之间的差异:如果段有实际的数据内容(.text 或 .data),elf_load_seg() 会通过调用 load_icode_mapper() 将这些内容从文件复制到对应的虚拟内存位置;对于 bss 段,不断分配页面直到达到 sgsize 指定的大小,所以新分配的页面不会从文件中复制任何数据,保持其内容为全0,自然就被初始化为全 0.

Thinking 6.6

1
2
3
4
5
6
7
8
// stdin should be 0, because no file descriptors are open yet
if ((r = opencons()) != 0) {
    user_panic("opencons: %d", r);
}
// stdout
if ((r = dup(0, 1)) < 0) {
    user_panic("dup: %d", r);
}

user/init.c 中的如上代码片段可以看出。

Thinking 6.7

外部命令,MOS 每次执行命令时都会通过 fork 创建一个子进程。

Linux 中的 cd 命令设计为内部命令,原因主要是:cd命令用于改变当前工作目录,这是一个与 shell 会话状态紧密相关的操作。作为内部命令,它可以确保改变立即生效并影响后续命令的执行环境。

Thinking 6.8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ ls.b | cat.b > motd
[00002803] pipecreate 
[00003805] destroying 00003805
[00003805] free env 00003805
i am killed ... 
[00004006] destroying 00004006
[00004006] free env 00004006
i am killed ... 
[00003004] destroying 00003004
[00003004] free env 00003004
i am killed ... 
[00002803] destroying 00002803
[00002803] free env 00002803
i am killed ... 

2 次 spawn:一次 spawn 启动 ls.b,另一次启动 cat.b

4次进程销毁。

实验难点分析

Lab6 的实验重点主要在于 Shell 的实现机制和管道通信。实验中,需要理解 Shell 程序的启动过程,此外,还需深入了解Shell的原理,包括如何读取用户命令输入、创建对应进程和处理进程间通信。总的来说,lab6 的综合性比较强,我们在完成整个 MOS 的过程是自底而上的,先完成底层的基本操作,再引入系统调用,逐渐步入用户态,然后是用户态的文件系统的实现,此时已经完全把 MOS 的搭建过程推进到了用户态上,而最后的 lab6 则是用户态的最顶层,需要综合使用此前搭建的所有模块内容。

实验体会

lab6 的实验内容相对来说比较友好,也没有上机测试。正如前文所说,lab6 是整个 MOS 的最顶层,综合之前的各种内容完成了 lab6 后, OS 课程也走向了终点。以这么一个综合性很强的 lab 为结尾,还是非常好的,真正让我们一个学期完成的内容走向了应用。一个学期的 OS 实验学习收获颇丰,非常感谢课程组的用心!

This post is licensed under CC BY 4.0 by the author.