logo资料库

Minix3源码解读报告.doc

第1页 / 共3页
第2页 / 共3页
第3页 / 共3页
资料共3页,全文预览结束
MINIX 3 源码解读报告 —— MINIX 3.1.6 时钟任务 1.时钟的作用 操作系统的时钟任务有很多作用,如维护系统时间、提供定时器、检测系统性能等,还有非常重要的一 点就是防止一个进程独占 CPU 资源。MINIX 3 是一个分时的交互式系统,多个程序共享同一资源时,需要 将 CPU 时间划分成多个时间片,分配给不同的进程,使每个进程都能得到调度。一个进程的运行时间是 否超过最大运行时间,需要由时钟来控制。 2.MINIX 3 的时钟驱动程序 MINIX 3.1.6 的时钟任务管理部分在 kernel/clock.c 的 clock_task()函数中定义。在函数的开始,调用 init_clock()设置一个看门狗时钟,用来周期性地调整进程调度队列。随后,它循环运行,等待一个消 息,然后分析消息来源:如果是 HARD_INT,则进行进一步处理,如果是其他消息,提示出错,进入下一 个循环。 init_clock()程序调用 balance_queues 初始化时钟,除了产生周期性中断之外,还将中断处理程序的地 址放在合适的地方,以便时钟芯片向中断控制芯片触发了 8 号中断时能够找到,并使能它以响应输入的 中断。 时钟中断处理程序在 MINIX 3.1.6 中有两种,一种是用于 boot processor 的 bsp_timer_int_handler(),一种是只用于 non-boot processor 的 ap_timer_int_handler()。前者也调 用后者。它们的区别在于,bsp_timer_int_handler()更新 realtime,并且在必要的时候发消息通知 clock_task()。 在每次时钟中断产生之后,中断处理程序开始运行。clock.c 中不提供具体的系统启动时间的计算,只维 护节拍计数器,提供当前节拍数给系统调用计算真实时间,这符合 MINIX 微内核的特性:功能性的模块 都交由外层的服务器来做。 当中断被禁止时,时钟节拍会丢失,使用一个全局变量 lost_ticks 来计算丢失的节拍数,再加上主计时 器 ticks,每次中断处理程序被激活时将 lost_ticks 清零。这个全局变量本身是由 kernel/arch/i386/klib386.s 中的 int86 函数使用的,int86 使用引导程序监控程序来管理对于 BIOS 的 控制,而监控程序返回在返回到内核之前 BIOS 调用忙期间 ecx 寄存器内对时钟节拍的计数值。 bsp_timer_int_handler()运行时,得到当前的 lost_ticks 数,于是更新 ticks 并清零 lost_ticks 使它 在下一轮重新计算: ticks = lost_ticks+1; lost_ticks = 0; 然后更新 realtime: realtime += ticks; 接下来才是真正调用时钟中断处理器 ap_timer_int_handler()。这个函数首先更新当前进程的用户时 间,如果它是一个用户进程,那么它将支付系统进程的时间。否则,它将从其他进程那里获得一些系统 时间。 p = proc_ptr; billp = bill_ptr;
p->p_user_time += ticks; if (priv(p)->s_flags & PREEMPTIBLE) { p->p_ticks_left -= ticks; } if (! (priv(p)->s_flags & BILLABLE)) { billp->p_sys_time += ticks; billp->p_ticks_left -= ticks; } 如果设置了定时器,就要计算新的剩余时间,并且检查是否到期。如果定时器的时间已经用完,则标记 变量 expired 为 1。 if ((p->p_misc_flags & MF_VIRT_TIMER) && (p->p_virt_left -= ticks) <= 0) expired = 1; if ((p->p_misc_flags & MF_PROF_TIMER) && (p->p_prof_left -= ticks) <= 0) expired = 1; if (! (priv(p)->s_flags & BILLABLE) && (billp->p_misc_flags & MF_PROF_TIMER) && (billp->p_prof_left -= ticks) <= 0) expired = 1; 接下来检查一个进程的虚拟定时器是否到期。当前进程和 bill_ptr 都要被检查,因为一个进程的 user_time 是另一个进程的 sys_time。 vtimer_check(p); if (p != billp) vtimer_check(billp); 平均负载被作为一队数组被保存在一个环形缓冲区内。 如果进程在 vtimer 更新后仍然是可调度的,检查它的剩余节拍数,以及它是否可抢占的。如果它的时钟 节拍数已经减小到 0,那么它就要被移出运行队列。 if (p->p_rts_flags == 0 && p->p_ticks_left <= 0 && priv(p)->s_flags & PREEMPTIBLE) { /* this dequeues the process */ RTS_SET(p, RTS_NO_QUANTUM); } 有时候用户进程需要设定一个时间,到达这个时间的时候由系统来通知该进程,这就要用到看门狗时 钟。在 MINIX 3 中,通知的方法是用一个同步警报将内核与用户空间联系起来。同步警报是以消息的形 式被传递的,只有当接收者执行了 receive 操作之后,才能被接收。如果该 notify 方法用来向一个接收 者通知一个警报消息,那么发送者不必阻塞,接收者也不必关心是否错过了一个警报消息,因为如果接 收者不是在等待该 notify 消息,那么它会被保存起来。 设置时间的函数是 set_timer(tp, exp_time, watchdog),其中参数 tp 是指向定时器的指针,exp_time 是一个 clock_t 变量,表示所定的期限;watchdog 是一个 tmr_func_t 变量,代表将被使用的看门狗时钟 函数。这个看门狗时钟是在其他地方定义的,它要做的就是实现像前面所述的那样,向设定时器的进程 发送一个消息。 在 kernel/system/do_setalarm.c 中定义了系统任务 do_setalarm,它有一个 timer_t 类型的指针 tp 指
向进程的定时器。执行 setalaram 的时候,tp 所指的 timer_t 结构中的 tmr_func 被设定为 cause_alarm,这就是一个看门狗时钟。它的代码仅仅包括两行: int proc_nr_e = tmr_arg(tp)->ta_int; lock_notify(CLOCK, proc_nr_e); 取得进程号,然后产生一个 notify,向该进程发送一个同步警报。do_setalarm 把 tp->tmr_exp_time 计 算出来,调用 kernel/clock.c 中的函数 set_timer,让时钟任务在定时器到点的时候调用 cause_alarm。
分享到:
收藏