Linux内核完全注释(20周年版·第2版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.3 Linux系统定时

在Linux 0.11内核中,PC的可编程定时芯片Intel 8253被设置成每隔10ms就发出一个时钟中断(IRQ0)信号。这个时间节拍就是系统运行的脉搏,我们称之为1个系统滴答。因此每经过1个滴答就会调用一次时钟中断处理程序(timer_interrupt)。该处理程序主要用来通过jiffies变量来累计自系统启动以来经过的时钟滴答数。每当发生一次时钟中断该值就增1。然后从被中断程序的段选择符中取得当前特权级CPL作为参数调用do_timer()函数。

do_timer()函数则根据特权级对当前进程运行时间做累计。如果CPL=0,则表示进程是运行在内核态时被中断,因此把进程的内核运行时间统计值stime增1,否则把进程用户态运行时间统计值增1。如果程序添加过定时器,则对定时器链表进行处理。若某个定时器时间到(递减后等于0),则调用该定时器的处理函数。然后对当前进程运行时间进行处理,把当前进程运行时间片减1。如果此时当前进程时间片还大于0,表示其时间片还没有用完,于是就退出do_timer()继续运行当前进程。如果此时进程时间片已经递减为0,表示该进程已经用完了此次使用CPU的时间片,于是程序就会根据被中断程序的级别来确定进一步处理的方法。若被中断的当前进程是工作在用户态的(特权级别大于0),则do_timer()就会调用调度程序schedule()切换到其他进程去运行。如果被中断的当前进程工作在内核态,即在内核程序中运行时被中断,则do_timer()会立刻退出。因此这样的处理方式决定了Linux系统在核态运行时不会被调度程序切换。进程在内核态程序中运行时是不可抢占的,但当处于用户态程序中运行时则是可以被抢占的。