minix 进程调度代码详解

上传人:第*** 文档编号:32690636 上传时间:2018-02-12 格式:DOCX 页数:4 大小:23.40KB
返回 下载 相关 举报
minix 进程调度代码详解_第1页
第1页 / 共4页
minix 进程调度代码详解_第2页
第2页 / 共4页
minix 进程调度代码详解_第3页
第3页 / 共4页
minix 进程调度代码详解_第4页
第4页 / 共4页
亲,该文档总共4页,全部预览完了,如果喜欢就下载吧!
资源描述

《minix 进程调度代码详解》由会员分享,可在线阅读,更多相关《minix 进程调度代码详解(4页珍藏版)》请在金锄头文库上搜索。

1、1.Minix3 中为每个进程分配的时间片,当进程的时间片用完后,将进行进程调度。进程的时间片以时钟滴答为单位进行分配。每次时钟中断,中断处理程序将减少当前进程的时间片。当时间片减小到 0 时,进行进程调度,选择一个合适的进程来拥有 CPU。Minix3 以每秒钟 60 次的频率进行时钟中断,即时钟中断处理程序每秒执行 60 次。每次执行,减少当前进程的时间片:/* Get number of ticks and update realtime. */ticks = lost_ticks + 1; /* lost_ticks 为 BIOS 中断所花费的时间 */lost_ticks = 0;

2、/* lost_ticks 清 0 */realtime += ticks; /* 更新时间 */proc_ptr-p_user_time += ticks; /* 更新当前进程的 user_time */if (priv(proc_ptr)-s_flags & PREEMPTIBLE) /* 如果进程可被抢占,则减少时间片 */proc_ptr-p_ticks_left -= ticks;if (! (priv(proc_ptr)-s_flags & BILLABLE) /* 如果当前进程能付费,则修改 sys_time 及减少时间片 */bill_ptr-p_sys_time += tic

3、ks;bill_ptr-p_ticks_left -= ticks;如果时间片用完,则向 clock_task 发送通知。因为该进程的时间片用完,需要重新调度,所以该进程就成为了上一个执行的进程。if(next_timeout p_ticks_leftp_ticks_lefts_flags & PREEMPTIBLE) lock_dequeue(prev_ptr); /* 将进程移出队列 */lock_enqueue(prev_ptr); /* 在将进程移入队列 */ lock_dequeue 函数将屏蔽中断,然后调用函数 dequeue 将进程移出就绪队列。而函数 lock_enqueue

4、同样将屏蔽中断,然后调用函数 enqueue。下面详细讨论enqueue 函数。4.enqueue 首先调用函数 sched,计算函数的优先级和应分配的时间片。如果该进程为前一次运行过的进程,即进程连续运行过两次,则降低进程的优先级。否则该进程可能无限期的占用 CPU。if ( ! time_left) /* 时间片是否用完 */rp-p_ticks_left = rp-p_quantum_size; /* 分配完整的时间片? */if (prev_ptr = rp) penalty +; /* 是否要降低进程优先级? */else penalty -; /* 进程都没执行过,则增加进程的优先

5、级 */prev_ptr = rp; /* 该进程刚运行过 */接下来,确定进程的优先级。Minix3 中,共有 16 个优先级队列,最高为 0,最低为15。进程优先级最大为其规定的优先级,最小不能小于 IDLE 进程的优先级,即最小为14。if (penalty != 0 & ! iskernelp(rp) /* 惩罚值不为 0,且该进程不是内核进程 */rp-p_priority += penalty; /* 根据惩罚值,确定新的优先级 */if (rp-p_priority p_max_priority) /* 最大为规定的最大优先级*/ rp-p_priority=rp-p_max_p

6、riority;else if (rp-p_priority IDLE_Q-1) /* 不能小于 IDLE 的优先级 */rp-p_priority = IDLE_Q-1;最后,返回进程的优先级。*queue = rp-p_priority;当进程的时间片未用完,则进程插入队列头部。用完则插入队列尾部。时间片未用完的原因有:1. 其要求的定时器到期; 2.进程请求了 I/O 操作而被阻塞。5.进程优先级确定后,就将其插入对应的优先级队列。这 16 个队列分别由rdy_head 数组指向每个队列的头和 rdy_tail 数组指向每个队列的尾。if (rdy_headq = NIL_PROC) /

7、* 如果队列为空 */ rdy_headq = rdy_tailq = rp; /* create a new queue */rp-p_nextready = NIL_PROC; /* mark new end */ else if (front) /* 队列非空,且插入头部。即时间片未用完 */rp-p_nextready = rdy_headq; /* chain head of queue */rdy_headq = rp; /* set new queue head */ else /* 插入队列尾部,即时间片用完 */rdy_tailq-p_nextready = rp; /* c

8、hain tail of queue */rdy_tailq = rp; /* set new queue tail */rp-p_nextready = NIL_PROC; /* mark new end */6.最后,调用函数 pick_proc 选择一个优先级最高的进程来拥有 CPU。从 16 个队列中,从最高的优先级队列开始,选择队头的进程来占有 CPU。for (q=0; q s_flags & BILLABLE) bill_ptr = rp; /* bill for system time */return; 最后,即将要运行的进程由 next_ptr 指针指示。7.enqueue

9、 函数结束后,将返回到函数 lock_enqueue。接着 lock_enqueue 将开中断,在中断处理函数运行完之后,内核跳转到_restart 处继续执行来完成进程的切换:save:cld ! set direction flag to a known valuepushad ! 保存通用寄存器o16 push ds ! save dso16 push es ! save eso16 push fs ! save fso16 push gs ! save gsmov dx, ss ! ss is kernel data segmentmov ds, dx ! load rest of k

10、ernel segmentsmov es, dx ! kernel does not use fs, gsmov eax, esp ! prepare to returnincb (_k_reenter) ! from -1 if not reenteringjnz set_restart1 ! 是否已经是内核堆栈,该情况发生在响应异常时mov esp, k_stktop ! 切换内核堆栈push _restart ! 中断处理完成后的返回地址入栈,即中断完成后转 restart 进行调度xor ebp, ebp ! for stacktracejmp RETADR-P_STACKBASE(e

11、ax) ! 返回到中断处理程序.align 4set_restart1: ! 检查到异常时,才会执行到此处push restart1jmp RETADR-P_STACKBASE(eax)上面的汇编代码是处理中断前保存现场信息的代码,其中在栈中压入了中断完成后的返回地址_restrart。当中断处理完成后,将转入_restart 代码启动一个进程。_restart:! Restart the current process or the next process if it is set. cmp (_next_ptr), 0 ! 是否有其他进程被调度,pick_proc 函数已经选择了一个进程

12、! 所以 next_ptr 不为 0jz 0f ! 如果没有调度其他进程,进继续执行前一个进程mov eax, (_next_ptr)mov (_proc_ptr), eax ! 调度新进程,proc_ptr = next_ptrmov (_next_ptr), 0 ! next_ptr 清 00: mov esp, (_proc_ptr) ! will assume P_STACKBASE = 0lldt P_LDT_SEL(esp) ! 装入新进程的局部描述符表(LDT)lea eax, P_STACKTOP(esp) ! 下一次中断的临时堆栈将建立在这地址之后mov (_tss+TSS3

13、_S_SP0), eax ! 将地址保存在 TSS 中restart1: ! 发生异常时从此处开始执行decb (_k_reenter)o16 pop gso16 pop fso16 pop eso16 pop dspopadadd esp, 4 ! skip return adriretd ! continue process下次中断的临时堆栈将建立在进程结构的 stackframe_p 结构的后面,硬件将保证临时堆栈不会溢出。最后的 iretd 指令将弹出一个 32 位的 EIP 值,然后再弹出一个 32位值并将最低的 2 个字节值传入 CS 寄存器,最后再弹出一个 32 位的标志寄存器值

14、。新进程开始执行。至此,一个完整的进程调度过程结束。下列几种情况将会启动_restart 函数:1.在系统启动时从 main 中启动;2.在硬件中断发生后从中断处理过程跳转到_restart ;3.在系统调用发生后从_s_call 调用它。iretd 指令的功能: IRETD pops EIP as 4 bytes, pops a further 4 bytes of which the top two are discarded and the bottom two go into CS, and pops the flags as 4 bytes as well, taking 12 bytes off the stack.IRETD 将先从 EIP 中弹出 4 字节;然后再弹出 4 字节,其中高 2 字节丢弃,低 2 字节装入 CS 寄存器;最后再弹出一个 4 字节的标志寄存器值。一共从堆栈中弹出 12 字节。

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 中学教育 > 职业教育

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号