超级能源强国起点:linux系统时间

来源:百度文库 编辑:九乡新闻网 时间:2024/07/04 21:09:28
5.6  系统时间和定时
5.6.1  系统时间
为了让操作系统能自动地准确提供当前时间和日期信息,PC/AT微机系统中提供了用电池供电的实时钟(Real Time,RT)电路支持。通常,这部分电路与保存系统信息的CMOS RAM集成在一个芯片上,因此这部分电路被称为RT/CMOS RAM电路。PC/AT微机或其兼容机中使用了Motorola公司的MC146818芯片。
在初始化时,Linux 0.12内核通过init/main.c程序中的time_init()函数读取这块芯片中保存的当前时间和日期信息,并通过kernel/mktime.c程序中的kernel_mktime()函数转换成从1970年1月1日午夜0时开始计起到当前的以秒为单位的时间,我们称之为UNIX日历时间。该时间确定了系统开始运行的日历时间,被保存在全局变量startup_time中供内核所有代码使用。用户程序可以使用系统调用time()来读取startup_time的值,而超级用户则可以通过系统调用stime()来修改这个系统时间值。
另外,再通过下面介绍的从系统启动开始计数的系统滴答值jiffies,程序就可以唯一地确定运行时刻的当前时间值。由于每个滴答定时值是10ms,因此内核代码中定义了一个宏来方便代码对当前时间的访问。这个宏定义在include/linux/sched.h文件第192行上,其形式如下:
#define CURRENT_TIME (startup_time + jiffies/HZ)
其中,HZ = 100,是内核系统时钟频率。当前时间宏CURRENT_TIME被定义为系统开机时间startup_time加上开机后系统运行的时间jiffies/100。在修改一个文件的被访问时间或其i节点的被修改时间时均使用了这个宏。5.6.2  系统定时
在Linux 0.12内核的初始化过程中,PC的可编程定时芯片Intel 8253(8254)的计数器通道0被设置成运行在方式3下(方波发生器方式),并且初始计数值LATCH被设置成每隔10ms在通道0输出端OUT发出一个方波上升沿。由于8254芯片的时钟输入频率为1.193180MHz,因此初始计数值LATCH=1193180/100,约为11931。由于OUT引脚被连接到可编程中断控制芯片的0级上,因此系统每隔10ms就会发出一个时钟中断请求(IRQ0)信号。这个时间节拍就是操作系统运行的脉搏,我们称之为1个系统滴答或一个系统时钟周期。因此每经过1个滴答时间,系统就会调用一次时钟中断处理程序(timer_interrupt)。
时钟中断处理程序timer_interrupt主要用来通过jiffies变量来累计自系统启动以来经过的时钟滴答数。每当发生一次时钟中断jiffies值就增1。然后调用C语言函数do_timer()作进一步的处理。调用时所带的参数CPL是从被中断程序的段选择符(保存在堆栈中的CS段寄存器值)中取得当前代码特权级CPL。
do_timer()函数则根据特权级对当前进程运行时间作累计。如果CPL=0,则表示进程运行在内核态时被中断,因此内核就会把进程的内核态运行时间统计值stime增1,否则把进程用户态运行时间统计值增1。如果软盘处理程序floppy.c在操作过程中添加过定时器,则对定时器链表进行处理。若某个定时器时间到(递减后等于0),则调用该定时器的处理函数。然后对当前进程运行时间进行处理,把当前进程运行时间片减1。时间片是一个进程在被切换掉之前所能持续运行的CPU时间,其单位是上面定义的滴答数。如果进程时间片值递减后还大于0,表示其时间片还没有用完,于是就退出do_timer()继续运行当前进程。如果此时进程时间片已经递减为0,表示该进程已经用完了此次使用CPU的时间片,于是程序就会根据被中断程序的级别来确定进一步处理的方法。若被中断的当前进程是工作在用户态的(特权级别大于0),则do_timer()就会调用调度程序schedule()切换到其他进程去运行。如果被中断的当前进程工作在内核态,即在内核程序中运行时被中断,则do_timer()会立刻退出。因此这样的处理方式决定了Linux系统的进程在内核态运行时不会被调度程序切换。即进程在内核态程序中运行时是不可抢占的(nonpreemptive) ,但当处于用户态程序中运行时则是可以被抢占的(preemptive)。
注意,上述定时器专门用于软盘马达开启和关闭定时操作。这种定时器类似现代Linux系统中的动态定时器(Dynamic Timer),仅供内核使用。这种定时器可以在需要时动态地创建,而在定时到期时动态地撤销。在Linux 0.12内核中定时器同时最多可以有64个。定时器的处理代码在sched.c程序283~368行。