硬件有一个时钟装置,该装置每隔一定时间发出一个时钟中断(称为一次时钟嘀嗒-tick),对应的中断处理程序就将全局变量jiffies_64加1
jiffies_64 是一个全局64位整型, jiffies全局变量为其低32位的全局变量,程序中一般用jiffies
HZ:可配置的宏,表示1秒钟产生的时钟中断次数,一般设为100或200
短延迟:忙等待
1. void ndelay(unsigned long nsecs)
2. void udelay(unsigned long usecs)
3. void mdelay(unsigned long msecs)
长延迟:忙等待
使用jiffies比较宏来实现
time_after(a,b) //a > b
time_before(a,b) //a < b
//延迟100个jiffies
unsigned long delay = jiffies + 100;
while(time_before(jiffies,delay))
{
;
}
//延迟2s
unsigned long delay = jiffies + 2*HZ;
while(time_before(jiffies,delay))
{
;
}
睡眠延迟----阻塞类
void msleep(unsigned int msecs);
unsigned long msleep_interruptible(unsigned int msecs);
延时机制的选择原则:
(1)定义定时器结构体
struct timer_list
{
struct list_head entry;
unsigned long expires; // 期望的时间值 jiffies + x * HZ
void (*function)(unsigned long); // 时间到达后,执行的回调函数,软中断异常上下文
unsigned long data;
};
(2)初始化定时器
init_timer(struct timer_list *)
(3)增加定时器 ------ 定时器开始计时
void add_timer(struct timer_list *timer);
(4)删除定时器 -------定时器停止工作
int del_timer(struct timer_list * timer);
(5)修改定时器
int mod_timer(struct timer_list *timer, unsigned long expires);
定义struct timer_list tl类型的变量
init_timer(...);//模块入口函数
//模块入口函数或open或希望定时器开始工作的地方
tl.expires = jiffies + n * HZ //n秒
tl.function = xxx_func;
tl.data = ...;
add_timer(....);
//不想让定时器继续工作时
del_timer(....);
void xxx_func(unsigned long arg)
{
......
mod_timer(....);//如需要定时器继续隔指定时间再次调用本函数
}
#include
#include
#include
#include
#include
#include
#include
#include "linux/timer.h"
#include
#include
#include
#define BUF_LEN 100
int major = 11;
int minor = 0;
int mysecond_num = 1;
struct mysecond_dev
{
struct cdev mydev;
int second;
struct timer_list timer;
atomic_t openflag;//1can open ,0 can not open
};
struct mysecond_dev gmydev;
void timer_func(unsigned long arg)
{
struct mysecond_dev *pmydev = (struct mysecond_dev *)arg;
pmydev->second++;
mod_timer(&pmydev->timer, jiffies + HZ * 1);
}
int mysecond_open(struct inode * pnode, struct file * pfile)
{
struct mysecond_dev *pmydev=NULL;
pfile->private_data =container_of(pnode->i_cdev,struct mysecond_dev,mydev);
pmydev=(struct mysecond_dev *)pfile->private_data;
printk("mysecond_open is called\n");
if(atomic_dec_and_test(&pmydev->openflag))
{
pmydev->timer.expires = jiffies + HZ * 1;
pmydev->timer.function=timer_func;
pmydev->timer.data=(unsigned long)pmydev;
add_timer(&pmydev->timer);
return 0;
}
else
{
atomic_inc(&pmydev->openflag);
printk("The device is opened already\n");
return -1;
}
return 0;
}
int mysecond_close(struct inode * pnode, struct file * filp)
{
struct mysecond_dev *pmydev=(struct mysecond_dev *)filp->private_data;
del_timer(&pmydev->timer) ;
atomic_set(&pmydev->openflag,1);
return 0;
}
ssize_t mysecond_read(struct file *pfile, char __user *puser ,size_t size,loff_t *p_pos)
{
struct mysecond_dev *pmydev = (struct mysecond_dev * )pfile->private_data;
int ret = 0;
if(size < sizeof(int))
{
printk("the expect read size is invalid\n");
return -1;
}
if(size >= sizeof(int))
{
size = sizeof(int);
}
ret = copy_to_user( puser , &pmydev->second , size);
if(ret)
{
printk("copy to user failed\n");
return -1 ;
}
return size;
}
struct file_operations myops = {
.owner = THIS_MODULE,
.open = mysecond_open,
.release=mysecond_close,
.read=mysecond_read,
};
int __init mysecond_init(void)
{
int ret = 0;
dev_t devno = MKDEV(major,minor);
/*申请设备号*/
ret = register_chrdev_region(devno,mysecond_num,"mysecond");
if (ret)
{
ret = alloc_chrdev_region(&devno, minor, mysecond_num, "mysecond");
if (ret)
{
printk("get devno failed\n");
return -1;
}
major = MAJOR(devno);//容易遗漏,注意
}
/*给struct cdev对象指定操作函数集*/
cdev_init(&gmydev.mydev, &myops);
/*将struct cdev对象添加到内核对应的数据结构里*/
gmydev.mydev.owner = THIS_MODULE;
cdev_add(&gmydev.mydev,devno,mysecond_num);
init_timer(&gmydev.timer);
atomic_set(&gmydev.openflag,1);
return 0;
}
void __exit mysecond_exit(void)
{
dev_t devno = MKDEV(major, minor);
cdev_del(&gmydev.mydev);
unregister_chrdev_region(devno,mysecond_num);
}
MODULE_LICENSE("GPL");
module_init(mysecond_init);
module_exit(mysecond_exit);