「BUAA OS Lab4-1-Extra」IPC实现阻塞机制避免发送方轮询
Part 0 前言
本篇博客记录Lab4-1-ExtraIPC实现阻塞机制避免发送方轮询的实现,Part 1为思路分析,Part 2为代码实现(经过重测已通过),Part 3 踩过的坑,读者可自取所需。
由于本次为线上上机,题目已经开源,不再在文中另附;如有需要者,可以联系yjk_official@foxmail.com获取。
Part 1 思路分析
本次题目加深了我对IPC和系统调用的理解,以下结合题目展开讲讲。
IPC与系统调用
首先需要明确,IPC是一种特殊的系统调用,遵循一般系统调用的规律。这里我们以writef
为例重温系统调用的一般流程:
- 调用
writef
这一用户函数 writef
中调用了用户空间的syscall_*
的用户空间函数(在user/lib.h
中声明,在user/syscall_lib.c
中实现)syscall_*
函数调用了msyscall
函数,进入内核态- 内核态中将异常分发到
handle_sys
函数,将系统调用所需要的信息传递到内核 - 内核获取信息,执行对应的内核空间的系统调用函数
sys_*
- 从系统调用函数返回,回到用户程序
writef
调用处
对照上述writef
的执行流程,下面介绍IPC流程:
IPC的接收方流程可以概括如下:
- 调用
user/ipc.c/ipc_recv
这一用户函数 ipc_send
中调用了用户空间中的user/syscall_lib.c/syscall_ipc_recv
syscall_ipc_can_send
调用了user/syscall_wrap.S/msyscall
函数,进入内核态- 内核将异常进行分发到
syscall.S/handle_sys
函数(事实上,msyscall
中调用了syscall
,Lab3中介绍过,syscall
会调用.text.exc_vec3代码段的代码进行异常分发,最终调用handle_sys
函数) - 内核获取信息,执行对应的内核空间的系统调用函数
syscall_all.c/sys_ipc_recv
- 从系统调用函数返回
IPC的发送方流程可以概括如下:
- 调用
user/ipc.c/ipc_send
这一用户函数 ipc_send
中调用了用户空间中的user/syscall_lib.c/syscall_ipc_can_send
syscall_ipc_can_send
调用了user/syscall_wrap.S/msyscall
函数,进入内核态- 内核将异常进行分发到
syscall.S/handle_sys
函数 - 内核获取信息,执行对应的内核空间的系统调用函数
syscall_all.c/sys_ipc_can_send
- 从系统调用函数返回
我们着重梳理了IPC过程,可以发现,我们的核心部分在于第五步,具体的系统调用实现函数sys_*
,这也是这次Extra的重点。
多进程
首先需要重点再强调的是,我们实现的是多进程操作系统。
多进程在IPC问题中的表现为,我们不确定发送方和接收方调用sys_ipc_can_send
和sys_ipc_recv
的相对先后顺序。因此,我们在sys_*
函数中,需要考虑调用本函数时可能存在的情况,以下具体分析。
接收进程
- 发送进程已经准备好了,目前在接收进程的等待队列中
- 接收进程的等待队列为空,说明发送进程还没有准备好(事实上,是发送进程还没运行到
sys_ipc_can_send
函数)
发送进程
- 接收进程已经准备好了
- 接收进程没有准备好,将这次发送的相关信息存到接收进程的等待队列
数据结构
上述分析中,当发送进程准备好而接收进程没有准备好的时候,我们将“相应信息”储存到接收进程对应的队列中。为了储存“相应信息”,我们构造如下数据结构:
1 | struct wait2sendList { |
这五项数据就已足够
Part 2 代码实现
sys_ipc_recv
1 | void sys_ipc_recv(int sysno, u_int dstva) |
sys_ipc_can_send
1 | int sys_ipc_can_send(int sysno, u_int envid, u_int value, u_int srcva, |
Part 3 踩过的坑
课下bug
本次Extra在上机时间没有做出来,其中一个原因就是课下有bug:
page_look_up
中pgdir
参数
在syscall_all.c/sys_ipc_can_send
中调用page_look_up
和page_insert
时,第一个参数本应为e->env_pgdir
,课下误写为其他内容。
想深一点发现,其实是对Lab2中内存管理的知识掌握得还不到位,如果很明确查找页面需要一级页表基地址,那这个bug也应该很容易发现了。
load_icode_mapper
中bzero
一方面,这个函数不需要调用bzero
;另一方面,bzero
函数的实现表明,其要求对齐,如果将没对齐的参数传入,可能会出现无输出等现象。
多进程认识不清
在课下写IPC部分代码时,没有过多考虑这是多进程问题,因此导致做题时没有清楚把握发送方和接收方都需要分类讨论这一点。
This is copyright.