内核定时器编程
实质上,时钟中断处理程序执行Update_process_timers()函数,该函数调用run_local_timers()函数,这个函数处理TIMER_SOFTIRQ软中断,运行当前处理器上到期的所有定时器。
Linux内核所提供的用于操作定时器的数据结构和函数如下:
1、time_list //在linux内核中,time_list结构体的一个实例对应一个定时器。
struct timer_list{
struct list_head entry;
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
struct timer_base_s *base;
}
struct timer_list my_timer;
2、初始化定时器
void init_timer(struct timer_list *timer);
3、增加定时器
void add_timer(struct timer_list *timer);
4、删除定时器
int del_timer(struct timer_list *timer);
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/timer.h>
#include <asm/atomic.h>
#define SECOND_MAJOR 250
static int second_major=SECOND_MAJOR;
struct second_dev{
struct cdev cdevp;
atomic_t counter;
struct timer_list s_timer;
/*
struct timer_list{
struct list_head list;
unsigned long expires;
unsigned long data; //device ID ,or something else
void (*function)(unsigned long); //when the timer is overfloat,the function will be executed
};
*/
};
struct second_dev *second_devp;
static void second_timer_handle(unsigned long arg){
mod_timer(&second_devp->s_timer,jiffies+HZ);//insert list
atomic_inc(&second_devp->counter); //counter+=1;
printk("current jiffies is %ld\n",jiffies);
/*全局变量jiffies用来记录自系统启动以来产生的节拍的总数。
启动时,内核将该变量初始化为0,此后,每次时钟中断处理程序都会增加该变量的值。
一秒内时钟中断的次数等于Hz,所以jiffies一秒内增加的值也就是Hz。*/
}
static int second_open(struct inode *inode,struct file *filp){
printk("now open the second char device .");
printk("the seconds is %d.",second_devp->counter);
/*初始化定时器*/
init_timer(&second_devp->s_timer);
second_devp->s_timer.function=&second_timer_handle;
second_devp->s_timer.expires=jiffies+HZ;
/*添加(注册)定时器*/
add_timer(&second_devp->s_timer);
atomic_set(&second_devp->counter,0);
return 0;
}
int second_release(struct inode *inode,struct file *filp){
/*删除定时器*/
del_timer(&second_devp->s_timer);
return 0;
}
static ssize_t second_read(struct file *filp,char __user *buf,size_t count,loff_t *ppos){
int counter;
counter=atomic_read(&second_devp->counter);
if(copy_to_user(buf,&counter,0x4))
return -EFAULT;
else return sizeof(unsigned int);
}
static const struct file_operations second_fops={
.owner=THIS_MODULE,
.open=second_open,
.release=second_release,
.read=second_read,
};
static void second_setup_cdev(struct second_dev *second_devp,int index){
int err,devno=MKDEV(second_major,index);
cdev_init(&second_devp->cdevp,&second_fops);
second_devp->cdevp.owner=THIS_MODULE;
second_devp->cdevp.ops=&second_fops;
err=cdev_add(&second_devp->cdevp,devno,1);
if(err)
printk("add the second cdev failly");
}
int __init second_init(){
int ret;
dev_t devno=MKDEV(second_major,0);
if(second_major)
ret=register_chrdev_region(devno,1,"second");
else
{
ret=alloc_chrdev_region(&devno,0,1,"second");
second_major=MAJOR(devno);
}
if(ret<0)
return ret;
second_devp=kmalloc(sizeof(struct second_dev),GFP_KERNEL);
if(!second_devp){
ret=-ENOMEM;
goto fail_malloc;
}
memset(second_devp,0,sizeof(struct second_dev));
second_setup_cdev(second_devp,0);
return 0;
fail_malloc:unregister_chrdev_region(devno,1);
}
void second_exit(void)
{
cdev_del(&second_devp->cdevp);
kfree(second_devp);
unregister_chrdev_region(MKDEV(second_major,0),1);
}
MODULE_AUTHOR("wang quan");
MODULE_LICENSE("Dual BSD/GPL");
module_param(second_major,int,S_IRUGO);
module_init(second_init);
module_exit(second_exit);