linux内核定时器

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/z1179675084/article/details/8741971

linux/timer.h头文件中定义了timer_list来描述一个内核定时器

struct timer_list {
	/*
	 * All fields that change during normal runtime grouped to the
	 * same cacheline
	 */
	struct list_head entry;//双向链表元素,用于将多个定时器连接成一条双向循环队列。
	unsigned long expires;//定时器节拍,定时一秒expries = jiffies + HZ*1
	struct tvec_base *base;

	void (*function)(unsigned long);//定时器处理函数
	unsigned long data;           //定时器处理函数参数

	int slack;

#ifdef CONFIG_
1.struct timer_list timer;
timer = TIMER_INITIALIZER(_function
#define TIMER_INITIALIZER(_function, _expires, _data) {		\
		.entry = { .prev = TIMER_ENTRY_STATIC },	\
		.function = (_function),			\
		.expires = (_expires),				\
		.data = (_data),				\
		.base = &boot_tvec_bases,			\
		__TIMER_LOCKDEP_MAP_INITIALIZER(		\
			__FILE__ ":" __stringify(__LINE__))	\
	}

定时器初始化

1. sttruct timer_list timer;
timer = TIMER_INITIALIZER(function,expries,data);

#define TIMER_INITIALIZER(_function, _expires, _data) {		\
		.entry = { .prev = TIMER_ENTRY_STATIC },	\
		.function = (_function),			\
		.expires = (_expires),				\
		.data = (_data),				\
		.base = &boot_tvec_bases,			\
		__TIMER_LOCKDEP_MAP_INITIALIZER(		\
			__FILE__ ":" __stringify(__LINE__))	\
	}

2.#define DEFINE_TIMER(_name, _function, _expires, _data)		\
	struct timer_list _name =				\
		TIMER_INITIALIZER(_function, _expires, _data)


3. //应事先对timer成员赋值
#define init_timer(timer)						\
	do {								\
		static struct lock_class_key __key;			\
		init_timer_key((timer), #timer, &__key);		\
	} while (0)


4//只需对expires赋值即可
#define setup_timer(timer, fn, data)					\
	do {								\
		static struct lock_class_key __key;			\
		setup_timer_key((timer), #timer, &__key, (fn), (data));\
	} while (0)

注册定时器
void add_timer(struct timer_list *timer)
{
	BUG_ON(timer_pending(timer));
	mod_timer(timer, timer->expires);
}

删除定时器

int del_timer(struct timer_list *timer)
{
	struct tvec_base *base;
	unsigned long flags;
	int ret = 0;

	timer_stats_timer_clear_start_info(timer);
	if (timer_pending(timer)) {
		base = lock_timer_base(timer, &flags);
		if (timer_pending(timer)) {
			detach_timer(timer, 1);
			if (timer->expires == base->next_timer &&
			    !tbase_get_deferrable(timer->base))
				base->next_timer = base->timer_jiffies;
			ret = 1;//定时器是活动的则置1
		}
		spin_unlock_irqrestore(&base->lock, flags);
	}

	return ret;
}
EXPORT_SYMBOL(del_timer);

修改定时器

int mod_timer(struct timer_list *timer, unsigned long expires)
{
	/*
	 * This is a common optimization triggered by the
	 * networking code - if the timer is re-modified
	 * to be the same thing then just return:
	 */
	if (timer_pending(timer) && timer->expires == expires)
		return 1;

	expires = apply_slack(timer, expires);

	return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
}
EXPORT_SYMBOL(mod_timer);


功能上等效于

del_timer(timer);
timer->expires=expires;
add_timer(timer);




展开阅读全文

Linux内核信号量和定时器问题请教:

01-14

rn正在学习用户态线程和内核态定时器的使用,有个问题请教大家:rnrn我在用户空间建立了一个线程,内核做一个字符驱动模块,通过ioctl调用来不断读取内核定时器有没有rnrn到期。在设备结构体里面加了一个信号量,在open调用的时候把信号量拿到,使用一个内核定时器,在内rnrn核定时器到期的处理函数里面释放信号量,这样用户线程调ioctl的时候就获取不到信号量了,等定时器rnrn超时了,就会释放信号量,这样ioctl就返回到用户空间了,可是下次再调用ioctl的时候就不等待信号量了,不知道为什么??rnrn不知道这样做行不行,看书上好像都是两个内核线程间用信号量来通信,请大家指教,谢谢!rnrnvoid timer_handle(void)rnrn int i = 0;rn mod_timer(&KDA_devp->s_timer,jiffies + HZ * 5); /*重新改变定时器的超时时间*/ rn up(&KDA_devp->sem); /*释放信号量,ioctl调用可以获取到该信号量*/rnrnrnrnint KDA_open(struct inode *inode, struct file *filp)rnrn rn struct KDA_dev *dev; /* device information */rnrn dev = container_of(inode->i_cdev, struct KDA_dev, cdev);rn filp->private_data = dev; /* for other methods */rn rn init_timer(&KDA_devp->s_timer);rn KDA_devp->s_timer.function = &timer_handle;rn KDA_devp->s_timer.expires = jiffies + HZ * 5;rn add_timer(&KDA_devp->s_timer); /*添加(注册)定时器*/rn down_interruptible(&dev->sem); /*获取信号量*/rn rn return 0;rnrnrnrnrnint KDA_ioctl(struct inode *inode, struct file *filp,rn unsigned int cmd, unsigned long arg)rnrn int err = 0;rn int isr_num = 100;rn rn struct KDA_dev *dev = filp->private_data; rn rn printk("want to get sem \n");rn rn down_interruptible(&dev->sem);rn rn switch(cmd)rn rn case 1 :rn printk("the case 1 \n");rn break;rn rn case 2 :rn printk("the case 2 \n"); rn break;rn rn case 3 :rn __put_user(KDA_devp->ISR_flag, (int __user *)arg); rn break; rn default:rn printk("the default case \n"); rn rn rn 论坛

没有更多推荐了,返回首页