内核中断下半部机制

下半部的主要任务就是执行中断相关的,不在中断处理器中执行的工作。如何将中断任务分为上下两部分分别执行呢,如下提供一些参考:

    • 如果工作对时间敏感,那么在中断处理器中执行。

    • 如果工作与硬件相关,在中断处理器中执行。

    • 如果工作需要确保另一个中断不能打断它,在中断处理器中执行。

    • 对于其他的情况,一般考虑在下半部中执行。

通常就尽量使中断处理程序快速完成,将一些不需要迅速处理的工作推迟到下半部中去执行。推迟是指现在暂时不执行,也不是在将来的某个特定时刻执行,而是在系统不是很忙的时候再执行。总的来说,上半部代码执行时一些或所有中断被禁用,而下半部代码在执行的时候所有的中断是打开的。

另一种推迟工作的机制是内核计时器,与下半部机制不同,计时器将工作推迟到某个指定的时间去执行。历史上和现在正在使用的下半部机制如下表所示:

BottomHalf

Status

BH

2.5中被移除

Taskqueues Softirq

Tasklet

2.5中被移除

2.3中开始出现

Workqueues

2.5中开始出现

微线程与软中断不同的地方是:微线程在同一时刻只能在一个处理器上运行。另外,不同的微线程可同时运行于不同的处理器上。

下半部之间的同步

微线程相对自己来说是串行的,即相同的微线程不会同时运行,即便是在不同的处理器上。所以无需考虑微线程之间的同步。

软中断没有提供串行化,所以所有共享的数据需要适当的锁定。

在进程上下文中,访问下半部共享数据,需要禁用下半部处理并在访问数据之前获得一个锁。

在中断上下文中,访问下半部共享数据,需要禁用中断并在访问数据之前获得一个锁。

任何在一个工作队列中的共享数据也需要锁定。

禁用下半部

通常情况下,仅仅禁用下半部是不够的,需要获得一个锁,并禁用下半部,特别是在驱动程序中。对于内核核心代码,只需要禁用下半部就行了。

禁用下半部的一些函数如下:

Method

Description

void local_bh_disable()

Disables softirq andtasklet processing on the local


processor

void local_bh_enable()

Enables softirq and taskletprocessing on the local


processor

这些调用可以被嵌套,当然它们调用的次数应该相同。即local_bh_disable()local_bh_enable()函数之间的调用次数应该相同。这些函数通过preempt_count(内核抢占与用户相同的计数器)来维护每个任务的计数器。这些函数对每个支持的平台来说是唯一的,下面是一些相同代码:

/*
* disable local bottom halves by incrementing the preempt_count
*/
void local_bh_disable(void)
{
struct thread_info *t = current_thread_info();
t ->preempt_count += SOFTIRQ_OFFSET;
}
/*
* decrement the preempt_count - this will ‘automatically’ enable
* bottom halves if the count returns to zero
*
* optionally run any bottom halves that are pending
*/
void local_bh_enable(void)
{
struct thread_info *t = current_thread_info();
t->preempt_count -= SOFTIRQ_OFFSET;
/*
* is preempt_count zero and are any bottom halves pending?
* if so, run them
*/
if (unlikely(!t->preempt_count && softirq_pending(smp_processor_id())))
do_softirq();
}

这些函数只对软中断和微线程有意义。


你可能感兴趣的:(Linux内核研究)