MIT 6.828 JOS/XV6 LAB4-partC

这一部分要实现抢占式调度和进程间通信

前面的调度是进程资源放弃CPU,但是实际中没有进程会这样做的,而为了不让某一进程耗尽CPU资源,需要抢占式调度,也就需要硬件定时

但是外部硬件定时在Bootloader的时候就关闭了,至今都没有开启

而JOS采取的策略是,在内核中的时候,外部中断是始终关闭的,而在用户态的时候,需要开启中断

所以首先需要求改IDT,但是我在之前把256个都弄好了

所以现在只需要在进入用户态的时候,保证外部中断是使能的就可以了,为了做到这一点,可以在每个进程初始化的时候就将外部中断使能位置位

在kern/env.c的env_alloc中

clip_image001

现在虽然中断使能已经打开,在用户态进程运行的时候,外部中断会产生并进入内核,但是现在还没有能处理这类中断

所以需要修改trap_dispatch,在发生外部定时中断的时候,调用调度器,调度另外一个可运行的进程

clip_image002

在跑make run-spin的时候,总是遇到bug,发现父进程调用sys_env_destroy没能把子进程杀死

找了半天,发现传入sys_env_destroy的参数是子进程的进程id,而在内核的系统调用sys_env_destroy中,却莫名其妙的变成了父进程的进程id,最后发现是syscall函数写错了

clip_image003

这一句的参数应该是a1,我却写成了curenv->env_id

这个问题显然是自lab3就有的,但是到现在才发现是错的,而且之前一直没有出错。。。

实现IPC

IPC是计算机系统中非常重要的一部分,而JOS选择了一种看起来挺别扭的方法来实现

两个进程需要通信的话,一方要发起recv,然后阻塞,直到有一个进程调用send向正在接受的进程发送了信息,阻塞的进程才会被唤醒

而JOS中,可以允许传递两种信息,一是一个32位整数,另外一个就是传递页的映射,在这个过程中,接收方和发送方将同时映射到一个相同的物理页,此时也就实现了内存共享

然后将这两个功能实现在了同一个系统调用中

首先看内核中的sys_ipc_recv函数。当一个进程试图去接收信息的时候,应该将自己标记为正在接收信息,而且为了不浪费CPU资源,应该同时标记自己为ENV_NOT_RUNNABLE,只有当有进程向自己发了信息之后,才会重新恢复可运行

clip_image004

将自己标记为不可运行之后,调用调度器运行其他进程

而内核中的sys_ipc_try_send的实现则相对来说麻烦很多,因为有很多的检测项,包括权限是否符合要求,要传送的页有没有,能不能将这一页映射到对方页表中去等等

clip_image005

如果srcva是在UTOP之下,那么说明是要共享内存,那就首先要在发送方的页表中找到srcva对应的页表项,然后在接收方给定的虚地址处插入这个页表项

接收完成之后,重新将当前进程设置为可运行,同时把env_ipc_recving设置为0,以防止其他的进程再发送,覆盖掉当前的内容

以上的两个函数都是系统调用,而在用户态下的函数调用需要另外实现

clip_image006

clip_image007

至此,整个lab4就实现完成了,好累。。。

posted @ 2016-01-06 13:58  bdhmwz  阅读(1486)  评论(0编辑  收藏  举报