Chinaunix首页 | 论坛 | 博客
  • 博客访问: 952283
  • 博文数量: 113
  • 博客积分: 7235
  • 博客等级: 少将
  • 技术积分: 2101
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-14 11:24
文章分类

全部博文(113)

文章存档

2013年(7)

2012年(5)

2011年(6)

2010年(8)

2009年(15)

2008年(72)

分类: LINUX

2008-09-17 18:08:22

在讲时钟中断以前,我们先来了解一些与时钟有关的硬件处理:
1):
实时时钟(RTC)
该时钟独立于CPU和其它芯片.即使PC断电,该时钟还是继续运行.该计时由一块单独的芯片处理,并把时钟值存放CMOS.该时间可参在IRQ8上周期性的产生时间信号.频率在2Hz ~ 8192Hz之间.但在linux,只是用RTC来获取当前时间.
2):
时间戳计时器(TSC)
CPU
附带了一个64位的时间戳寄存器,当时钟信号到来的时候.该寄存器内容自动加1
3):
可编程中断定时器(PIC)
该设备可以周期性的发送一个时间中断信号.发送中断信号的间隔可以对其进行编程控制.linux系统中,该中断时间间隔由HZ表示.这个时间间隔也被称为一个节拍(tick).
4):CPU
本地定时器
在处理器的本地APIC还提供了另外的一定定时设备.CPU本地定时器也可以单次或者周期性的产生中断信号.与上次描述的PIC相比.它有以下几点的区别:
APIC
本地计时器是32.PIC16.由此APIC本地计时器可以提供更低频率的中断信号
本地APIC只把中断信号发送给本地CPU.PIC发送的中断信号任何CPU都可以处理
APIC
定时器是基于总线时钟信号的.PIC有自己的内部时钟振荡器
5):
高精度计时器(HPET)
linux2.6中增加了对HPET的支持.HPET是一种由微软和intel联合开发的新型定时芯片.该设备有一组寄时器,每个寄时器对应有自己的时钟信号,时钟信号到来的时候就会自动加1.
实际上,intel多理器系统与单处理器系统还有所不同:
在单处理系统中.所有计时活动过由PIC产生的时钟中断信号触发的
在多处理系统中,所有普通活动是由PIC产生的中断触发.所有具体的CPU活动,都由本地APIC触发的.

HPET Support
HPET Timer Support
是一个新的特性,HPET intel 制定的新的用以代替传统的8254(PIT)中断定时器与RTC 的定时器,全称叫作高精度事件定时器。如果你有一台较新的机器就选它吧,一般它是一个安全的选项,即使你的硬件不支持HPET 也不会造成损害.

以上内容摘自http://hi.baidu.com/80695073/blog/item/9c170f55be0ae5c1b745ae5b.html

2.6.23内核中,我们知道当一个中断发生时,中断的执行过程是内核经过一系列的跳转最后调用do_IRQ()来相应(处理)该中断。而do_IRQ()最终调用的是注册在irq_desc数组对应项的处理函数。例如对于时钟中断来说,最终处理时钟中断的函数是注册在irq_desc[0]中的处理函数。接下来我们就看看到底注册的时钟中断处理函数是什么。

我们使用命令cat /proc/interrupt可以查看到当前系统中已经注册的中断,其中时钟中断的中断号为0,由此我们可以知道系统的时钟中断处理函数是注册在irq_desc[0](更多关于irq_desc数组的信息请查看include/linux/irq.h)里的中断处理函数。由/proc/interrupt我们也可以知道irq_desc[0].name=”timer”。由此我们可以在内核里找到irq0

static struct irqaction irq0 = {

.handler = timer_interrupt,

.flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,

.mask = CPU_MASK_NONE,

.name = "timer"

};


该结构给出了两个信息。一个是0号中断的名字是“timer”,另一个是中断的处理函数是timer_interrupt。由此我们可以断定irq0便是时钟中断描述符。它的注册过程必然是setup_irq(0,&irq0)。这一节我们主要讲时钟中断的注册过程,下一节讲时钟中断处理函数timer_interrupt

我们使用cscope(一个很好用的在本地阅读内核源码的工具)可以很轻松的找到一个函数在内核里都被那些函数调用。所以我们找到了timer_init_hook(),这里调用setup_irq(0,&irq0)来注册时钟中断。依次我们找到了时钟中断的注册过程:

start_kernel()

|-->time_init()

   |-->tsc_init();

   |-->late_time_init=choose_time_init();/*choose_time_init()=hpet_time_init*/

|-->late_time_init()

   |-->time_init_hook(); /*hpet_enable()函数调用之后*/

             |-->setup_irq(0, &irq0);

                    |-->irq_desc[0].action.handler=timer_interrput;

我们都知道linux内核启动的C程序入口就是start_kernel,在start_kernel里,内核会进行一系列的初始化,其中就包括时钟中断。start_kernel()调用time_init()来初始化时间戳计数器(Time Stamp Counter TSC),另外将函数指针late_time_init赋值为hpet_time_init。之后在start_kernel()里有:

if (late_time_init)

   late_time_init();

先前在time_init()里已经将late_time_init赋值为hpet_time_init了,所以此处便是调用hpet_time_init()函数。该函数就会调用time_init_hook()。这样时钟中断就被注册了。


阅读(2997) | 评论(1) | 转发(1) |
给主人留下些什么吧!~~

chenjifeng2008-09-21 16:51:22

收获了