《linux内核源码分析----定时器》

来看一下linux kernel的定时器是如何设定的

timer.h

#ifndef _LINUX_TIMER_H
#define _LINUX_TIMER_H

/*
 * DON'T CHANGE THESE!! Most of them are hardcoded into some assembly language
 * as well as being defined here.
 */

/*
 * The timers are:
 *
 * BLANK_TIMER		console screen-saver timer
 *
 * BEEP_TIMER		console beep timer
 *
 * RS_TIMER		timer for the RS-232 ports
 *
 * SWAP_TIMER		timer for the background pageout daemon
 * 
 * HD_TIMER		harddisk timer
 *
 * HD_TIMER2		(atdisk2 patches)
 *
 * FLOPPY_TIMER		floppy disk timer (not used right now)
 * 
 * SCSI_TIMER		scsi.c timeout timer
 *
 * NET_TIMER		tcp/ip timeout timer
 *
 * COPRO_TIMER		387 timeout for buggy hardware..
 *
 * QIC02_TAPE_TIMER	timer for QIC-02 tape driver (it's not hardcoded)
 *
 * MCD_TIMER		Mitsumi CD-ROM Timer
 *
 * GSCD_TIMER		Goldstar CD-ROM Timer
 *
 */

#define BLANK_TIMER	0
#define BEEP_TIMER	1
#define RS_TIMER	2
#define SWAP_TIMER	3

#define HD_TIMER	16
#define FLOPPY_TIMER	17
#define SCSI_TIMER 	18
#define NET_TIMER	19
#define SOUND_TIMER	20
#define COPRO_TIMER	21

#define QIC02_TAPE_TIMER	22	/* hhb */
#define MCD_TIMER	23

#define HD_TIMER2	24
#define GSCD_TIMER	25

#define DIGI_TIMER	29

// 固定定时器
struct timer_struct {
	unsigned long expires;
	void (*fn)(void);
};

extern unsigned long timer_active;
extern struct timer_struct timer_table[32];

/*
 * This is completely separate from the above, and is the
 * "new and improved" way of handling timers more dynamically.
 * Hopefully efficient and general enough for most things.
 *
 * The "hardcoded" timers above are still useful for well-
 * defined problems, but the timer-list is probably better
 * when you need multiple outstanding timers or similar.
 *
 * The "data" field is in case you want to use the same
 * timeout function for several timeouts. You can use this
 * to distinguish between the different invocations.
 */
struct timer_list {
	struct timer_list *next;
	struct timer_list *prev;
	unsigned long expires;
	unsigned long data;
	void (*function)(unsigned long);
};

extern void add_timer(struct timer_list * timer);
extern int  del_timer(struct timer_list * timer);

extern void it_real_fn(unsigned long);

extern inline void init_timer(struct timer_list * timer)
{
	timer->next = NULL;
	timer->prev = NULL;
}

#endif

sched.c

unsigned long timer_active = 0;				//32bit,每个Bit代表一个定时器节点是否有定时任务挂靠(true有效)
struct timer_struct timer_table[32];		// 在linux1.0之前的版本,很多数据结构是固定size的,无法扩容。从1.3开始引入链表、哈希表、二叉树等可以扩展的结构。本文是1.3版本,上下兼容。因此既固定写死的数组,也有用链表实现的。

/*
 * The head for the timer-list has a "expires" field of MAX_UINT,
 * and the sorting routine counts on this..
 */
static struct timer_list timer_head = { &timer_head, &timer_head, ~0, 0, NULL };
#define SLOW_BUT_DEBUGGING_TIMERS 0



void add_timer(struct timer_list * timer)
{
	unsigned long flags;
	struct timer_list *p;

#if SLOW_BUT_DEBUGGING_TIMERS
	if (timer->next || timer->prev) {
		printk("add_timer() called with non-zero list from %p\n",
			__builtin_return_address(0));
		return;
	}
#endif
	p = &timer_head;
	save_flags(flags);					// 保存中断屏蔽字
	cli();								// 禁止中断控制器
	do {								/* 将timer加入timer_head链表的合适位置(timeout顺序为从小到大) */
		p = p->next;
	} while (timer->expires > p->expires);
	timer->next = p;
	timer->prev = p->prev;
	p->prev = timer;
	timer->prev->next = timer;
	restore_flags(flags);				// 恢复中断屏蔽字、使能中断控制器
}


int del_timer(struct timer_list * timer)
{
	int ret = 0;
	if (timer->next) {				// 如果timer是timer_head链表的节点,则从链表的环取下
		unsigned long flags;
		struct timer_list * next;
		save_flags(flags);
		cli();
		if ((next = timer->next) != NULL) {
			(next->prev = timer->prev)->next = next;
			timer->next = timer->prev = NULL;
			ret = 1;
		}
		restore_flags(flags);
	}
	return ret;
}


static inline void run_timer_list(void)
{
	struct timer_list * timer;

	// 变量整条timer_head链表(双向循环有头链表),执行超时的定时器节点的callback函数
	while ((timer = timer_head.next) != &timer_head && timer->expires <= jiffies) {
		void (*fn)(unsigned long) = timer->function;
		unsigned long data = timer->data;
		timer->next->prev = timer->prev;
		timer->prev->next = timer->next;
		timer->next = timer->prev = NULL;
		sti();
		fn(data);
		cli();
	}
}

static inline void run_old_timers(void)
{
	struct timer_struct *tp;
	unsigned long mask;

	// 变量定时器数组,执行超时的定时器的callback函数,并关闭该定时器(所有老定时器的设置,都是one shot,而不是period)
	for (mask = 1, tp = timer_table+0 ; mask ; tp++,mask += mask) {
		if (mask > timer_active)
			break;
		if (!(mask & timer_active))
			continue;
		if (tp->expires > jiffies)
			continue;
		timer_active &= ~mask;
		tp->fn();
		sti();
	}
}
发布了95 篇原创文章 · 获赞 75 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/jacky128256/article/details/105037427
今日推荐