Linux的动态定时器-时间轮
作者:网络转载 发布时间:[ 2014/8/22 10:35:06 ] 推荐标签:操作系统 Linux 软件开发
其中,timer_list是具体定时器的结构体(后面再具体看timer_list结构体);上面包含tv1,tv2,tv3,tv4,tv5;内核定时器的巧妙设计在于此。
#define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6)
#define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 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)
struct tvec {
struct list_head vec[TVN_SIZE];
};
struct tvec_root {
struct list_head vec[TVR_SIZE];
};
从这个定义看到,tv1是长度为256的数组,数组成员是list_head;同样的,tv2,tv3,tv4和tv5都是长度为64的数组,数组成员是list_head。List_head是linux内核代码中广泛使用的双向链表。在阻塞和非阻塞中的等待队列时看到了list_head的应用。那么,tv1-tv5都是数组+链表的实现,其实hash的有一种简单实现是数组+链表的组合,那么这几个有些hash的味道,具体是不是,还要分析道后面才知道。
再回到前面的初始化中,
for(j = 0; j < TVN_SIZE; j++) {
INIT_LIST_HEAD(base->tv5.vec+ j);
INIT_LIST_HEAD(base->tv4.vec+ j);
INIT_LIST_HEAD(base->tv3.vec+ j);
INIT_LIST_HEAD(base->tv2.vec+ j);
}
for(j = 0; j < TVR_SIZE; j++)
INIT_LIST_HEAD(base->tv1.vec+ j);
tv1-tv5这5个结构体中的数组中每个list_head进行初始化。
base->timer_jiffies= jiffies;
base->next_timer= base->timer_jiffies;
将base中的timer_jiffies和next_timer都初始化为jiffies。
初始化完成后,在init_timers函数的第二个重要的步骤是:
open_softirq(TIMER_SOFTIRQ,run_timer_softirq);
这个函数注册定时器软中断,简单的软中断分析见《linux的软中断》;
下面来看具体定时器的初始化和添加操作:
初始化的函数:
#define init_timer(timer)
do {
static struct lock_class_key __key;
init_timer_key((timer), #timer, &__key);
} while (0)
void init_timer_key(struct timer_list *timer,
const char *name,
struct lock_class_key *key)
{
debug_init(timer);
__init_timer(timer, name, key);
}
static void __init_timer(struct timer_list *timer,
const char *name,
struct lock_class_key *key)
{
timer->entry.next = NULL;
timer->base = __raw_get_cpu_var(tvec_bases);
#ifdef CONFIG_TIMER_STATS
timer->start_site = NULL;
timer->start_pid = -1;
memset(timer->start_comm, 0, TASK_COMM_LEN);
#endif
lockdep_init_map(&timer->lockdep_map, name, key, 0);
}
初始化的宏定义:
<span style="font-family:'Liberation Serif', serif;">#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__))
}
</span>
定时器的添加:
void add_timer(struct timer_list *timer)
{
BUG_ON(timer_pending(timer));
mod_timer(timer, timer->expires);
}
Timer_list结构体的定义:
struct timer_list {
struct list_head entry;
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
struct tvec_base *base;
#ifdef CONFIG_TIMER_STATS
void *start_site;
char start_comm[16];
int start_pid;
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
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;
return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
}
1、 if(timer_pending(timer) && timer->expires == expires)
return1;
如果该timer已经在已经加入了timer_base中的某个向量(tv1—tv5)中,函数什么也不做,直接返回。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
Linux下开源的DDR压力测试工具曝Linux恶意软件:让树莓派设备挖掘数字货币linux系统中不同颜色的文件夹及根目录介绍软件测试工程师必知必会Linux命令Linux下DNS服务器配置如何成为不可替代的Linux运维工程师?详解Linux进程(作业)的查看和杀死Linux 日志定时轮询流程详解比特币勒索病毒不只Windows系统有,Linux版的来了Linux日志定时轮询流程详解Linux iommu和vfio概念空间解构Linux系统如何低于TCP洪水攻击Linux无损调整分区大小Linux下防火墙配置实例Linux使用Jexus托管Asp.Net Core应用程序Linux中引号的那些事

sales@spasvo.com