linux内核分析之软定时器笔记

定时器是一种软件功能,即允许在将来的某个时刻,函数在给定的时间间隔用完时被调用。超时表示与定时器相关的时间间隔已经用完的那个时刻。

linux上考虑两种类型的定时器,即动态定时和间隔定时器。第一种类型由内核使用,而间隔定时器由进程在用户态创建。

动态定时器

动态定时的主要数据结构是一个叫做tvec_bases的per cpu变量,他包含NR_CPUS个元素,系统中每个CPU都有一个。每个元素是一个tvec_base_t类型的数据结构,他包含相应CPU中处理动态定时器需要的所有数据。

struct tvec_base { spinlock_t lock; struct timer_list *running_timer; unsigned long timer_jiffies; unsigned long next_timer; struct tvec_root tv1; struct tvec tv2; struct tvec tv3; struct tvec tv4; struct tvec tv5; } ____cacheline_aligned;

字段tv1的数据解雇为tvec_root_t类型,包含一个vec数组,这个数组由256个list_head元素组成(即256个动态定时器链表组成)。这个结构包含了在紧接着到来的255个节拍内将要到期的所有动态定时器。

字段tv2,tv3和tv4的数据结构都是tvec_t类型,该类型有一个数组vec。这些链表包含在紧接着到来的2^14-1/2^20-1以及2^26-1个节拍内将要到期的所有动态定时器。

字段tv5与前面的字段几乎相同,但唯一区别就是vec数组的最后一项是一个大expires字段值得动态定时器链表。tv5从不需要从其他的数组补充。

动态定时器编程

1,申请timer_list结构并对其初始化,其中必须初始化的有expires,function

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 };

2,调用init_timer函数初始化

该函数最终调用下面函数

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); }

可看到初始化的几个相关变量。

3,调用add_timer函数将申请的timer_list结构添加到合适的链表

该函数最终调用如下函数添加到对应的链表

static void internal_add_timer(struct tvec_base *base, struct timer_list *timer) { unsigned long expires = timer->expires; unsigned long idx = expires - base->timer_jiffies; struct list_head *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); }

其中对于定时器的修改、删除等操作,内核提供了相应的函数。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值