核心定時器編程
實質上,時鐘中斷處理常式執行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 250static 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 elsevoid (*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);