linux内核定时中断最小时间,Linux内核中断及定时器实现

内核中断及定时器实现分析

定时器是Linux提供的一种定时服务的机制。它在某个特定的时间唤醒某个进程,来做一些工作。Linux初始化时,init_IRQ()函数设定8253的定时周期为10ms(一个tick值)。同样,在初始化时,time_init()用setup_irq()设置时间中断向量irq0,中断服务程序为timer_interrupt。

在2.4版内核及较早的版本当中,定时器的中断处理采用底半机制,底半处理函数的注册在start_kernel()函数中调用sechd_init(),在这个函数中又调用init_bh(TIMER_BH, timer_bh)注册了定时器的底半处理函数。然后系统才调用time_init()来注册定时器的中断向量和中断处理函数。

在中断处理函数timer_interrupt()中,主要是调用do_timer()函数完成工作。do_timer()函数的主要功能就是调用mark_bh()产生软中断,随后处理器会在合适的时候调用定时器底半处理函数timer_bh()。在timer_bh()中,实现了更新定时器的功能。2.4.23版的do_timer()函数代码如下(经过简略):

void do_timer(struct pt_regs *regs)

{

(*(unsigned long *)&jiffies)++;

update_process_times(user_mode(regs));

mark_bh(TIMER_BH);

}

而在内核2.6版本以后,定时器中断处理采用了软中断机制而不是底半机制。时钟中断处理函数仍然为timer_interrup()-> do_timer_interrupt()-> do_timer_interrupt_hook()-> do_timer()。不过do_timer()函数的实现有所不同:

void do_timer(struct pt_regs *regs)

{

jiffies_64++;

update_process_times(user_mode(regs));

update_times();

}

两者所调用的函数基本相同,但是2.4.23版内核与2.6.6内核中,对于update_process_times()函数的实现不同:

void update_process_times(int user_tick)

{

struct task_struct *p = current;

int cpu = smp_processor_id(), system = user_tick ^ 1;

update_one_process(p, user_tick, system, cpu);

run_local_timers();

scheduler_tick(user_tick, system);

}

update_process_times()调用run_local_timers()引起TIMER_SOFTIRQ定时器软中断,处理器在随后的合适的时机运行软中断处理函数run_timer_softirq,这个函数是在init_timers()函数中注册的:

void __init init_timers(void)

{

timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,

(void *)(long)smp_processor_id());

register_cpu_notifier(&timers_nb);

open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);

}

事实上软中断处理函数run_timer_softirq()并没有做什么工作,主要的任务还是通过调用__run_timers()函数完成的,这个函数相当于2.4.23内核当中的run_timer_list()函数的功能。

static inline void __run_timers(tvec_base_t *base)

{

struct timer_list *timer;

spin_lock_irq(&base->lock);

/*这里进入定时器处理循环,利用系统全局jiffies与定时器基准jiffies进行对比,如果前者大,则表明有某些定时器需要进行处理了,否则表示所有的定时器都没有超时*/

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;

/*

在时间列表数据结构当中查找是否存在需要进行超时处理的定时器,时间列表的数据结构定义如下:

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;

*/

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

fn(data);

spin_lock_irq(&base->lock);

goto repeat;

}

}

set_running_timer(base, NULL);

spin_unlock_irq(&base->lock);

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值