内核定时器的用法及原理

内核定时器timer的使用demo

#include <linux/init.h>  
#include <linux/module.h>  
#include <linux/timer.h>
#include <linux/rtc.h>

#define SHOW_DL_TIME
#define WAY1
//#define WAY2
//#define WAY3

#ifdef SHOW_DL_TIME
struct timex  txc;
struct rtc_time tm;
#endif

#ifdef WAY3
	static void timer_function(unsigned long arg);
	static DEFINE_TIMER(timer, timer_function, 0, 0);
#else
 	struct timer_list timer;
#endif

static void timer_function(unsigned long arg) 
{ 
//	printk(KERN_INFO "%s\n",__FUNCTION__);
	mod_timer(&timer, jiffies + 2*HZ);  //重新开始计时
#ifdef SHOW_DL_TIME
	do_gettimeofday(&(txc.time));
	rtc_time_to_tm(txc.time.tv_sec,&tm);
	pr_err("%s#########:: %d-%d-%d %d:%d:%d \n", __func__, tm.tm_year+1900,tm.tm_mon, tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec);
#endif
} 
     
static int timer_init(void) 
{ 
	printk(KERN_INFO "%s\n",__FUNCTION__);
#if defined(WAY1)
	init_timer(&timer);
	timer.data=100;
	timer.function=timer_function;
#elif defined(WAY2)
	setup_timer(&timer, timer_function, 100);
#else
#endif
	timer.expires=jiffies+2*HZ;
	add_timer(&timer);
	return 0; 
} 
     
static void timer_exit(void) 
{      
	printk(KERN_INFO "%s\n",__FUNCTION__);
	del_timer(&timer);  
} 
     
module_init(timer_init); 
module_exit(timer_exit);  
MODULE_LICENSE("Dual BSD/GPL"); 

      内核定时器有以上三种方法来初始化,通过定义不同的宏使用不同方法,当定时时间到,打印相应的时间,通过对比两次打印,可知道定时的时间。

工作原理

软中断类型

enum
{
	HI_SOFTIRQ=0,
	TIMER_SOFTIRQ,
	NET_TX_SOFTIRQ,
	NET_RX_SOFTIRQ,
	BLOCK_SOFTIRQ,
	BLOCK_IOPOLL_SOFTIRQ,
	TASKLET_SOFTIRQ,
	SCHED_SOFTIRQ,
	HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the numbering. Sigh! */
	RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */
	NR_SOFTIRQS
};

内核初始化设立TIMER_SOFTIRQ的处理函数run_timer_softirq

void __init init_timers(void)
{
	open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
}
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
	softirq_vec[nr].action = action;
}

看下run_timer_softirq,找出超时的定时器,运行其超时处理函数

static void run_timer_softirq(struct softirq_action *h)
{
	struct tvec_base *base = this_cpu_ptr(&tvec_bases);

	if (time_after_eq(jiffies, base->timer_jiffies))
		__run_timers(base);
}

static inline void __run_timers(struct tvec_base *base)
{
	while (!hlist_empty(head)) {
		void (*fn)(unsigned long);
		unsigned long data;
		bool irqsafe;
		timer = hlist_entry(head->first, struct timer_list, entry);
		fn = timer->function;
		data = timer->data;
		call_timer_fn(timer, fn, data);	
}

static void call_timer_fn(struct timer_list *timer, void (*fn)(unsigned long),unsigned long data)
{
	fn(data);
}

那在什么时机处理定时器的超时呢
//ARM generic timer(arm_timer 用于更新时间/进程调度/高精度定时器唤醒等)
在arm_timer中断发生后,运行run_local_timers,标志有TIMER_SOFTIRQ发生

void run_local_timers(void)
{
	raise_softirq(TIMER_SOFTIRQ);
}

void __raise_softirq_irqoff(unsigned int nr)
{
	trace_softirq_raise(nr);
	or_softirq_pending(1UL << nr);//设置相应的软中断标志位,这里是TIMER_SOFTIRQ
}

void irq_enter(void)
{
	preempt_count_add(HARDIRQ_OFFSET);
}

/*
 * This function must run with irqs disabled!
 */
inline void raise_softirq_irqoff(unsigned int nr)
{
	__raise_softirq_irqoff(nr);

	/*
	 * If we're in an interrupt or softirq, we're done
	 * (this also catches softirq-disabled code). We will
	 * actually run the softirq once we return from
	 * the irq or softirq.
	 *
	 * Otherwise we wake up ksoftirqd to make sure we
	 * schedule the softirq soon.
	 */
	if (!in_interrupt())  //in_interrupt()==true
		wakeup_softirqd();
}

void raise_softirq(unsigned int nr)
{
	unsigned long flags;

	local_irq_save(flags);
	raise_softirq_irqoff(nr);
	local_irq_restore(flags);
}

中断后面会执行

void irq_exit(void)
{
        preempt_count_sub(HARDIRQ_OFFSET);
	if (!in_interrupt() && local_softirq_pending())//in_interrupt()==false
		invoke_softirq();
}

static inline void invoke_softirq(void)
{
	do_softirq_own_stack();
}

static inline void do_softirq_own_stack(void)
{
	__do_softirq();
}

asmlinkage __visible void __do_softirq(void)
{
	__u32 pending;
	int softirq_bit;
	pending = local_softirq_pending();
	h = softirq_vec;
	while ((softirq_bit = ffs(pending))) {
		unsigned int vec_nr;
		h += softirq_bit - 1;
		vec_nr = h - softirq_vec;
		h->action(h);//调用TIMER_SOFTIRQ的处理函数run_timer_softirq
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值