下面是从源代码抽离出来的与timer有关的代码。
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <asm/hardirq.h>
int delay = HZ; /* the default delay, expressed in jiffies */
module_param(delay, int, 0);
MODULE_AUTHOR("Alessandro Rubini");
MODULE_LICENSE("Dual BSD/GPL");
/*
* The timer example follows
*/
int tdelay = 10;
module_param(tdelay, int, 0);
/* This data structure used as "data" for the timer and tasklet functions */
struct jit_data {
struct timer_list timer;
struct tasklet_struct tlet;
int hi; /* tasklet or tasklet_hi */
wait_queue_head_t wait;
unsigned long prevjiffies;
unsigned char *buf;
int loops;
};
#define JIT_ASYNC_LOOPS 5
void jit_timer_fn(unsigned long arg)
{
struct jit_data *data = (struct jit_data *)arg;
unsigned long j = jiffies;
data->buf += sprintf(data->buf, "%9li %3li %i %6i %i %s\n",
j, j - data->prevjiffies, in_interrupt() ? 1 : 0,
current->pid, smp_processor_id(), current->comm);
if (--data->loops) {
data->timer.expires += tdelay;
data->prevjiffies = j;
add_timer(&data->timer);
} else {
wake_up_interruptible(&data->wait);
}
}
/* the /proc function: allocate everything to allow concurrency */
int jit_timer(char *buf, char **start, off_t offset,
int len, int *eof, void *unused_data)
{
struct jit_data *data;
char *buf2 = buf;
unsigned long j = jiffies;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
init_timer(&data->timer);
init_waitqueue_head (&data->wait);
/* write the first lines in the buffer */
buf2 += sprintf(buf2, " time delta inirq pid cpu command\n");
buf2 += sprintf(buf2, "%9li %3li %i %6i %i %s\n",
j, 0L, in_interrupt() ? 1 : 0,
current->pid, smp_processor_id(), current->comm);
/* fill the data for our timer function */
data->prevjiffies = j;
data->buf = buf2;
data->loops = JIT_ASYNC_LOOPS;
/* register the timer */
data->timer.data = (unsigned long)data;
data->timer.function = jit_timer_fn;
data->timer.expires = j + tdelay; /* parameter */
add_timer(&data->timer);
/* wait for the buffer to fill */
wait_event_interruptible(data->wait, !data->loops);
if (signal_pending(current))
return -ERESTARTSYS;
buf2 = data->buf;
kfree(data);
*eof = 1;
return buf2 - buf;
}
int __init jit_init(void)
{
create_proc_read_entry("jitimer", 0, NULL, jit_timer, NULL); // 创建/proc/jitimer 文件,读取该文件时,jit_timer函数被掉用。
return 0; /* success */
}
void __exit jit_cleanup(void)
{
remove_proc_entry("jitimer", NULL);
}
module_init(jit_init);
module_exit(jit_cleanup);
测试:
编译完成放在网络文件系统后插入模块。
读取/proc/jitimer文件
输出为:
# cat /proc/jitimer
time delta inirq pid cpu command
-26656 0 0 677 0 cat
-26646 10 1 0 0 swapper
-26636 10 1 0 0 swapper
-26626 10 1 0 0 swapper
-26616 10 1 0 0 swapper
-26606 10 1 0 0 swapper
time是一堆负值???? jiffies不是 unsigned long ,初始值为0吗? --->LDD3 p184
过了一会再次读取time变成正值
# cat /proc/jitimer
time delta inirq pid cpu command
24538 0 0 672 0 cat
24548 10 1 0 0 swapper
24558 10 1 0 0 swapper
24568 10 1 0 0 swapper
24578 10 1 0 0 swapper
24588 10 1 0 0 swapper
经过查阅,发现jiffies的初始值定义在这里:include/linux/jiffies.h:
/*
* Have the 32 bit jiffies value wrap 5 minutes after boot
* so jiffies wrap bugs show up earlier.
*/
#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))
说明是有意定义成-300×HZ.
-300 转换成 unsigned long 是很大的一个正数。
long -300 = unsigned long 4294966996
也就是说jiffies会在 300秒后溢出。(300*HZ 表示300秒)
这样做的目的看上面的注释就明白了。
这样做就使得系统在启动后 5 分钟时发生 jiffies 回绕。这么做有利于在早期设备驱动程序因 jiffies 回绕导致的逻辑错误,方便驱动程序的开发。
参考: http://wenku.baidu.com/view/d7a940f904a1b0717fd5dd49.html