Modern interrupt handlers are divided into a
top half and a bottom half. The top half consists of everything that has to be
executed before releasing the CPU, to preserve data. The bottom half contains
everything that can be done at relative leisure.
-
Only one old-style bottom half can run at any time, regardless
of the number of CPUs (kernel 2.2).
-
Only one instance of each tasklet can run at any time.
Different tasklets can run concurrently on different CPUs. This means that given
any tasklet, there is no need to enforce any serialization because already it is
enforced by the kernel: you cannot have multiple instances of the same tasklet
running concurrently.
-
Only one instance of each softirq can run at the same time on a
CPU. However, the same softirq can run on different CPUs concurrently. This
means that given any softirq you need to make sure that accesses to shared data
by different CPUs use proper locking. To increase parallelization, the softirqs
should be designed to access only per-CPU data as much as possible, reducing the
need for locking considerably.
jiffes是个全局变量, 系统开机后每1毫秒加1(1毫秒为1个系统滴答)。发生一次系统时钟中断即为一个滴答。 -- HZ = 1000表示系统1秒发生1000次时钟中断,也就是1毫秒发生一次时钟中断,jiffies同时也会递增1。
volatile的含义是向编译器指明变量的内容可能会由于被其他程序修改而变化。要求代码在引用该变量时一定要从指定的内存位置取值。即是要求gcc不
要对jiffies进行优化处理,也不要挪动位置,并且要从内存中取值。因为时钟中断处理程序会修改它的值。
注:通常在程序中声明一个变量时(没有volatile修饰),编译器会尽量把它存放在通用寄存器中(如ebx),以提高访问效率。当CPU把其值放到
ebx中后一般就不会再关心该变量对应内存位置中的内容。若此时其他程序(如内核程序或一个中断过程)修改了内存中该变量的值,ebx中的值并不会随之更
新。
时钟中断与jiffies
------------------------------------------------------
jiffies用来统计系统自运行以来的时钟中断的次数,每次时钟中断都会使jiffies的加1,jiffies超过最大值后就会溢出,循环为0。
时钟中断是可以屏蔽的,当使用关中断指令关闭系统中断后,时钟中断将被屏蔽,jiffies的值也就停止不变化。而在关闭了系统中断后,时钟中断被屏蔽,
也就不会发生新的任务调度。除非有不可屏蔽的中断被检测到,执行完中断后,执行调度程序。因此,可以使用关/开系统中断来达到使用不可重入变量或者代码的
目的,但是要注意关闭中断的时间要尽量短,不然会增加系统的响应时间。
printk("<1>HZ = %d\n", HZ); // 1000
printk("<1>jiffies_to_msecs(HZ) = %d ms\n", jiffies_to_msecs(HZ)); // 1000 ms
printk("<1>msecs_to_jiffies(10) = %ld jiffies\n", msecs_to_jiffies(10)); // 10 jiffies
printk("<1>jiffies_to_usecs(10) = %d us\n", jiffies_to_usecs(10)); // 10000 us
printk("<1>usecs_to_jiffies(2000) = %ld jiffies\n", usecs_to_jiffies(2800)); // 3 jiffies 时钟的处理类似中断,也是登记一个时间处理函数,在预定的时间过后,系统会调用这个函数,在include/linux/timer.h中声明。
struct timer_list{
struct timer_list *next;
struct timer_list *prev;
unsigned long expires;
unsigned long data;
void (*function) (unsigned long);
};
void add_timer(struct timer_list *timer);
void del_timer(struct timer_list *timer);
void init_timer(struct timer_list *timer);
|
使用时钟,先声明一个timer_list结构,调用init_timer对它进行初始化。
timer_list结构里的expires标明这个时钟的周期,单位采用jiffies的单位。jiffies是linux一个全局变量,代表时间。它的单位随硬件平台的不同而不同。系统里定义了一个常数HZ,代表每秒钟最小时间间隔的数目。这样jiffies的单位就是1/HZ。启动时,kernel将该变量初始为0,每次时钟中断处理程序timer_interrupt()将该变量加1。因为一秒钟内增加的时钟中断次数等于HZ,所以jiffies一秒内增加的值也是HZ。Intel平台jiffies的单位是1/100s,这就是系统所能分辨的最小时间间隔了。所以expires/HZ就是以秒为单位的这个时钟的周期。
function就是时间到了以后的回调函数,它的参数就是timer_list中的data。data这个参数在初始化时钟的时候赋值,一般赋给它设备的device结构指针。在预置时间到系统调用function,同时系统把这个timer_list从定时队列里清除。所以如果需要一直使用定时函数,要在function里再次调用add_timer()函数。
每一次时钟中断都会把全局变量jiffies加一。这就意味着,在任何时刻,jiffies代表从开机到现在所发生的嘀哒的数量。
如果一个函数需要测量时间间隔,它可以把当前的jiffies值保存到一个局部变量中,然后把这个值与后续时刻的jiffies相比较以求的它们之间的差值。通过这个差值(两个时刻间的嘀哒数量)就可以计算出从计时开始经过了多长时间。
下面的例子展示了一个函数,它需要执行一些任务,但是它占用cpu的时间不能超过一个嘀哒数。当do_something完成时,它把job_done置为一个非零值,然后函数就可以返回了。
unsigned long start_time = jiffies;
int job_done = 0;
do{
do_something(&job_done);
if(job_done)
return;
}while(jiffies - start_time < 1);
|
晶振--->时钟中断(CPU时钟中断引脚)
阅读(1625) | 评论(0) | 转发(0) |