好记性不如铅笔头

kernel, linux

Linux的内核定时器timer的简单记录

Linux内核实现的timer在LDD3中讲解的非常清楚,这里就简单的笔记下部分代码注释吧。

【 Linux-2.6.11/kernel/timer.c 】

/*
 * per-CPU timer vector definitions:
 */
#define TVN_BITS 6
#define TVR_BITS 8
#define TVN_SIZE (1 << TVN_BITS)
#define TVR_SIZE (1 << TVR_BITS)
#define TVN_MASK (TVN_SIZE - 1)
#define TVR_MASK (TVR_SIZE - 1)

typedef struct tvec_s {
	struct list_head vec[TVN_SIZE];
} tvec_t;

typedef struct tvec_root_s {
	struct list_head vec[TVR_SIZE];
} tvec_root_t;

struct tvec_t_base_s {
	spinlock_t lock;
	unsigned long timer_jiffies;
	struct timer_list *running_timer;
	tvec_root_t tv1;
	tvec_t tv2;
	tvec_t tv3;
	tvec_t tv4;
	tvec_t tv5;
} ____cacheline_aligned_in_smp;

typedef struct tvec_t_base_s tvec_base_t;

static inline void set_running_timer(tvec_base_t *base,
					struct timer_list *timer)
{
#ifdef CONFIG_SMP
	base->running_timer = timer;
#endif
}

/* Fake initialization */
static DEFINE_PER_CPU(tvec_base_t, tvec_bases) = { SPIN_LOCK_UNLOCKED };


/* 定时器无效后打印堆栈函数 */
static void check_timer_failed(struct timer_list *timer)
{
    static int whine_count;/* 静态变量 */
	if (whine_count < 16) {
		whine_count++;
		printk("Uninitialised timer!\n");
		printk("This is just a warning.  Your computer is OK\n");
		printk("function=0x%p, data=0x%lx\n",
			timer->function, timer->data);
		dump_stack();
	}
	/*
	 * Now fix it up
	 */
    spin_lock_init(&timer->lock);/* 初始化定时器里面的自旋锁  */
    timer->magic = TIMER_MAGIC; /* 赋值magic,便于校验 */
}
/* 检查一个定时器是否有效 */
static inline void check_timer(struct timer_list *timer)
{/* 如果定时器的magic不匹配,说明定时器变量出错了 */
	if (timer->magic != TIMER_MAGIC)
		check_timer_failed(timer);
}

/* 添加定时器的内部实现函数 */
/* PS:个人感觉这个函数的最后可以增加
timer->base = new_base;
*/
static void internal_add_timer(tvec_base_t *base, struct timer_list *timer)
{
    unsigned long expires = timer->expires;/* 获取定时器到期时间(绝对值) */
    unsigned long idx = expires - base->timer_jiffies;/*获取当前时间和定时器到期时间的相对值*/
	struct list_head *vec;
/*
根据相对值的大小,将定时器变量添加到对应的链表中,即vec
*/
	if (idx < TVR_SIZE) {
		int i = expires & TVR_MASK;
		vec = base->tv1.vec + i;
	} else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
		int i = (expires >> TVR_BITS) & TVN_MASK;
		vec = base->tv2.vec + i;
	} else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
		int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
		vec = base->tv3.vec + i;
	} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
		int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
		vec = base->tv4.vec + i;
	} else if ((signed long) idx < 0) {
		/*
		 * Can happen if you add a timer with expires == jiffies,
		 * or you set a timer to go off in the past
		 */
		vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK);
	} else {
		int i;
		/* If the timeout is larger than 0xffffffff on 64-bit
		 * architectures then we use the maximum timeout:
		 */
		if (idx > 0xffffffffUL) {
			idx = 0xffffffffUL;
			expires = idx + base->timer_jiffies;
		}
		i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
		vec = base->tv5.vec + i;
	}
	/*
	 * Timers are FIFO:
	 */
    /* 将定时器添加到指定的链表中 */
	list_add_tail(&timer->entry, vec);
}

/* 修改定时器的到期时间 */
int __mod_timer(struct timer_list *timer, unsigned long expires)
{
	tvec_base_t *old_base, *new_base;
	unsigned long flags;
	int ret = 0;

	BUG_ON(!timer->function);

    /* 首先看下定时器是否有效 */
	check_timer(timer);

    /* 先锁定定时器,同时关闭中断   */
	spin_lock_irqsave(&timer->lock, flags);
    new_base = &__get_cpu_var(tvec_bases);//获取当前CPU对应的定时器链表集
repeat:
    old_base = timer->base;//获取要修改的定时器之前存放的链表集

	/*
	 * Prevent deadlocks via ordering by old_base < new_base.
	 */
	if (old_base && (new_base != old_base)) {
		if (old_base < new_base) {
			spin_lock(&new_base->lock);
			spin_lock(&old_base->lock);
		} else {
			spin_lock(&old_base->lock);
			spin_lock(&new_base->lock);
		}
		/*
		 * The timer base might have been cancelled while we were
		 * trying to take the lock(s):
		 */
		if (timer->base != old_base) {
			spin_unlock(&new_base->lock);
			spin_unlock(&old_base->lock);
			goto repeat;
		}
	} else {
		spin_lock(&new_base->lock);
		if (timer->base != old_base) {
			spin_unlock(&new_base->lock);
			goto repeat;
		}
	}

	/*
	 * Delete the previous timeout (if there was any), and install
	 * the new one:
	 */
/* 如果定时器之前有存放在链表中,就把它从老的链表中删掉 */
	if (old_base) {
		list_del(&timer->entry);
		ret = 1;
	}
    /* 然后更新定时器变量,然后插入到链表中 */
	timer->expires = expires;
    internal_add_timer(new_base, timer);//这里的第一个参数是新的链表集
	timer->base = new_base;

	if (old_base && (new_base != old_base))
		spin_unlock(&old_base->lock);
	spin_unlock(&new_base->lock);
	spin_unlock_irqrestore(&timer->lock, flags);

	return ret;
}

EXPORT_SYMBOL(__mod_timer);

/***
 * add_timer_on - start a timer on a particular CPU
 * @timer: the timer to be added
 * @cpu: the CPU to start it on
 *
 * This is not very scalable on SMP. Double adds are not possible.
 */

/* 将定时器加入到指定的CPU中 */
void add_timer_on(struct timer_list *timer, int cpu)
{
    /*获取指定CPU对应的链表集*/
	tvec_base_t *base = &per_cpu(tvec_bases, cpu);
  	unsigned long flags;
  
    /* 定时器的回调函数不能为空,而且定时器不能已经被注册 */
  	BUG_ON(timer_pending(timer) || !timer->function);

    /* 校验定时器 */
	check_timer(timer);
/* 加锁,添加 */
	spin_lock_irqsave(&base->lock, flags);
	internal_add_timer(base, timer);
    timer->base = base;/* 注意这里更新了base变量 */
	spin_unlock_irqrestore(&base->lock, flags);
}


/***
 * mod_timer - modify a timer's timeout
 * @timer: the timer to be modified
 *
 * mod_timer is a more efficient way to update the expire field of an
 * active timer (if the timer is inactive it will be activated)
 *
 * mod_timer(timer, expires) is equivalent to:
 *
 *     del_timer(timer); timer->expires = expires; add_timer(timer);
 *
 * Note that if there are multiple unserialized concurrent users of the
 * same timer, then mod_timer() is the only safe way to modify the timeout,
 * since add_timer() cannot modify an already running timer.
 *
 * The function returns whether it has modified a pending timer or not.
 * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
 * active timer returns 1.)
 */
/* 修改定时器的到期时间 */
int mod_timer(struct timer_list *timer, unsigned long expires)
{
	BUG_ON(!timer->function);

	check_timer(timer);

	/*
	 * 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->expires == expires && timer_pending(timer))
		return 1;

    /* 调用内部函数 */
	return __mod_timer(timer, expires);
}

EXPORT_SYMBOL(mod_timer);

/***
 * del_timer - deactive a timer.
 * @timer: the timer to be deactivated
 *
 * del_timer() deactivates a timer - this works on both active and inactive
 * timers.
 *
 * The function returns whether it has deactivated a pending timer or not.
 * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
 * active timer returns 1.)
 */
/* 删掉一个定时器,这里并不等待定时器完成。同步版本是下面的函数 */
int del_timer(struct timer_list *timer)
{
	unsigned long flags;
	tvec_base_t *base;

	check_timer(timer);

/* 防止定时器对应的集合被变更,不停地加锁,检测 */
repeat:
 	base = timer->base;
	if (!base)
		return 0;
	spin_lock_irqsave(&base->lock, flags);
	if (base != timer->base) {
		spin_unlock_irqrestore(&base->lock, flags);
		goto repeat;
	}
    /* 将定时器从集合中删除 */
	list_del(&timer->entry);
	/* Need to make sure that anybody who sees a NULL base also sees the list ops */
    smp_wmb();/* 防止编译器优化。  */
	timer->base = NULL;
	spin_unlock_irqrestore(&base->lock, flags);

	return 1;
}

EXPORT_SYMBOL(del_timer);

#ifdef CONFIG_SMP
/***
 * del_timer_sync - deactivate a timer and wait for the handler to finish.
 * @timer: the timer to be deactivated
 *
 * This function only differs from del_timer() on SMP: besides deactivating
 * the timer it also makes sure the handler has finished executing on other
 * CPUs.
 *
 * Synchronization rules: callers must prevent restarting of the timer,
 * otherwise this function is meaningless. It must not be called from
 * interrupt contexts. The caller must not hold locks which would prevent
 * completion of the timer's handler.  Upon exit the timer is not queued and
 * the handler is not running on any CPU.
 *
 * The function returns whether it has deactivated a pending timer or not.
 *
 * del_timer_sync() is slow and complicated because it copes with timer
 * handlers which re-arm the timer (periodic timers).  If the timer handler
 * is known to not do this (a single shot timer) then use
 * del_singleshot_timer_sync() instead.
 */
/* 删掉一个定时器,如果定时器在执行,就等待它结束在返回 */
int del_timer_sync(struct timer_list *timer)
{
	tvec_base_t *base;
	int i, ret = 0;

	check_timer(timer);

del_again:
    ret += del_timer(timer);//首先从链表集中尝试删除该定时器

    for_each_online_cpu(i) {
        base = &per_cpu(tvec_bases, i);//在所有的CPU中查找该定时器对应的CPU
		if (base->running_timer == timer) {
            /*
            如果能找到该CPU,而且该定时器也在执行,此时就放弃CPU,并且允许内核抢占。
            */
            while (base->running_timer == timer) {
				cpu_relax();
                preempt_check_resched();//允许内核抢占,并发起调度
			}
			break;
		}
	}
	smp_rmb();
    if (timer_pending(timer))//如果定时器没有被删除,重试,
		goto del_again;

	return ret;
}
EXPORT_SYMBOL(del_timer_sync);

/***
 * del_singleshot_timer_sync - deactivate a non-recursive timer
 * @timer: the timer to be deactivated
 *
 * This function is an optimization of del_timer_sync for the case where the
 * caller can guarantee the timer does not reschedule itself in its timer
 * function.
 *
 * Synchronization rules: callers must prevent restarting of the timer,
 * otherwise this function is meaningless. It must not be called from
 * interrupt contexts. The caller must not hold locks which wold prevent
 * completion of the timer's handler.  Upon exit the timer is not queued and
 * the handler is not running on any CPU.
 *
 * The function returns whether it has deactivated a pending timer or not.
 */
/* 删除一个非周期的定时器 */
int del_singleshot_timer_sync(struct timer_list *timer)
{
	int ret = del_timer(timer);

	if (!ret) {
		ret = del_timer_sync(timer);
		BUG_ON(ret);
	}

	return ret;
}
EXPORT_SYMBOL(del_singleshot_timer_sync);
#endif

/* 工具函数,将链表集tv中的某一个index下的所有的定时器添加到base集中  */
static int cascade(tvec_base_t *base, tvec_t *tv, int index)
{
	/* cascade all the timers from tv up one level */
	struct list_head *head, *curr;

	head = tv->vec + index;
	curr = head->next;
	/*
	 * We are removing _all_ timers from the list, so we don't  have to
	 * detach them individually, just clear the list afterwards.
	 */
    /* 循环便利tv+index中的定时器,将它们加入到base中 */
	while (curr != head) {
		struct timer_list *tmp;

		tmp = list_entry(curr, struct timer_list, entry);
		BUG_ON(tmp->base != base);
		curr = curr->next;
		internal_add_timer(base, tmp);
	}
    /* 直接重新初始化原来的链表头就可以去掉原来的关联了。 */
	INIT_LIST_HEAD(head);

	return index;
}

/***
 * __run_timers - run all expired timers (if any) on this CPU.
 * @base: the timer vector to be processed.
 *
 * This function cascades all vectors and executes all expired timer
 * vectors.
 */
#define INDEX(N) (base->timer_jiffies >> (TVR_BITS + N * TVN_BITS)) & TVN_MASK

/* 遍历并执行某个链表集下的所有的定时器 */
static inline void __run_timers(tvec_base_t *base)
{
	struct timer_list *timer;

	spin_lock_irq(&base->lock);
    while (time_after_eq(jiffies, base->timer_jiffies)) {
		struct list_head work_list = LIST_HEAD_INIT(work_list);
		struct list_head *head = &work_list;
 		int index = base->timer_jiffies & TVR_MASK;
 
		/*
		 * Cascade timers:
		 */
		if (!index &&
			(!cascade(base, &base->tv2, INDEX(0))) &&
				(!cascade(base, &base->tv3, INDEX(1))) &&
					!cascade(base, &base->tv4, INDEX(2)))
			cascade(base, &base->tv5, INDEX(3));
		++base->timer_jiffies; 
		list_splice_init(base->tv1.vec + index, &work_list);
repeat:
		if (!list_empty(head)) {
			void (*fn)(unsigned long);
			unsigned long data;

			timer = list_entry(head->next,struct timer_list,entry);
 			fn = timer->function;
 			data = timer->data;

			list_del(&timer->entry);
			set_running_timer(base, timer);
			smp_wmb();
			timer->base = NULL;
			spin_unlock_irq(&base->lock);
			{
				u32 preempt_count = preempt_count();
				fn(data);
				if (preempt_count != preempt_count()) {
					printk("huh, entered %p with %08x, exited with %08x?\n", fn, preempt_count, preempt_count());
					BUG();
				}
			}
			spin_lock_irq(&base->lock);
			goto repeat;
		}
	}
	set_running_timer(base, NULL);
	spin_unlock_irq(&base->lock);
}

 

发表评论

1 + 13 =

此站点使用 Akismet 来减少垃圾评论。了解我们如何处理您的评论数据