思路整理¶
辅助¶
解释一下pstat结构: 这是一系列进程的集合(类似一个列表),其中的结构成员都是数组,每个索引i对应一个进程。每个进程刻画了以下属性:该进程是否可用、进程分配得到的票数、进程的pid、以及他总共分得的时间片。
一些待解决的关键问题:
ptable在哪里被定义?为什么到处都在用?
ans:在proc.c的开头就被定义,并且在initlock中,初始化了ptable.lock。而他的proc[NPROC]是怎么初始化的?这个我真不知道额。
这个process for Nice有什么用? Ticket_set_for_process有什么用?
没有任何用,我已经删了(。
怎么porc.c中的setticket的?
- 首先,在proc.h中对struct proc进行修改,新增了in_use(进程是否可用),ticket(该进程的票数),ticks和tick(有什么用?)。 同时,在这个文件中增加了一个“设置进程票数”的函数声明。
- 接下来进入proc.c。首先,在include中先引入pstat.h(主要是为了引入数据结构pstat)和rand.h(在scheduler中使用),并且增加一个全局变量all_tickets。
- 铺垫:在spinlock.c中存在一个acquire函数,这个函数负责获得锁。相应的,有一个release函数,负责释放锁。
- 进入setticket函数(形参为number)。首先,初始化一个proc指针pr作为一个新进程。然后立刻上锁。注意,此时的锁对象是ptable,这个结构体包含一个spinlock,以及一个porc结构体数组。通俗地说,ptable是所有进程的一个索引表。
- 接下来,再新建一个临时的proc指针p作为进程迭代的变量。进入一个for循环,这个循环检索所有的进程,如果遇到了本次新建的进程(用pid作为标准,但通俗地说,条件是p==pr),则把预设的票数传入这个进程p。
怎么实现porc.c中的getpinfo(形参为pstat的ps)?
- 先上锁(ptable.lock),然后又定义一个proc指针p作为迭代变量。
- 然后根据ptable中的proc,给ps的各个进程的各结构成员赋值。
- 退出锁。
- 进入sysproc.c文件,在sys_getpinfo中,使用argptr获得用户空间传递的结构体指针ps。
- 调用getpinfo函数
怎么在创建并初始化彩票信息?
- 进入proc.c函数,首先修改allocproc。认识到这个函数大概是用来给proc分配空间的。只要在found板块中初始ticket和tick即可。
- 在fork函数中np的初始化过程中,加入ticket项。
调整调度算法
- 首先,初始化了两个结构体指针,即proc p和cpu c。其中,cpu结构体中含有proc结构体指针,表示正在cpu上执行的process。
- 然后进入一个退出条件在循环内部的for循环。
- 首先,使用sti()允许对这个处理器进行中断(即可以打破外层循环)。同时,初始化一个cur_total进行当前总票数的统计。再上锁。
- 接下来,使用 getRunnableProcTickets() 算出总票数,其中1LL是为了在运算中临时扩容。
- 通过随机库(rand.c)给出一个随机数,作为中奖的彩票。
- 接下来,把p作为迭代变量,对ptable.proc[]中的进程进行遍历。
- 如果p可以在准备运行的就绪状态(RUNNABLE),则使当前的总票数加上中奖的票数。否则跳过。注意状态一共有六种(UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE)
- 如果如果当前票数小于总票数,则continue;当前票数大于等于总票数,则该进程中奖,设置cpu当前运行的进程为p,然后用switchuvm()使cpu转向当前进程。注意,我们是在进程中释放ptable.lock的锁,并在回到这个函数时再次获得它(就好像我们没有开过锁一样)。
- 调整p的状态为running,并且令tick_start=ticks(在trap.c中定义,描述总共进行的时间片)。然后用swtch切换上下文,使这个进程开始运行。(该操作在proc.h中定义proc时说明)
- 再次获得ticks(此时的ticks是执行了p之后的)为tick_end,此时相减,就能够获得p的时间片数目。(最初想要直接p->tick++,但是这样做显然忽略了一个进程可能会使用多个时间片的事实)
- 再次调用switchkvm(),使得p的状态在返回前被更改。
- 重置cpu的进程为0。并且让内层循环结束。
- 释放锁。
其他文件修改
在syscall.h中,添加了SYS_yield\SYS_settickets\SYS_getpinfo三个函数的编号(宏定义形式)。
在syscall.c中,先在使用extern关键字的声明群中声明一系列函数(包括sys_yield等),然后再在后面的函数指针引用它们。
在defs.h中,添加新增的结构体pstat。
在param.h中,添加一个初始化常数InitialTickets,这个常数表示没有特殊说明,进程的票数都是5.
在usys.S中,添加SYSCALL(yield), SYSCALL(settickets), SYSCALL(getpinfo)等。
在user.h中,添加struct pstat和settickets与getpinfo两个函数(我们在彩票调度中新增的函数)。
在pstat.h中,定义了一个新的结构体pstat,这个结构体能够说明inuse(是否使用),ticket(每个进程的票数),pid,tick(每个进程所用的时间片数)。
在testTicket.c中,获得用户输入的命令行参数,然后设置票数。
在testProCInfo.c中,把所有进程的参考信息都打印出来(参照实验手册)。