转自:http://blog.csdn.net/tommy_wxie/article/details/7425712

版权声明:本文为博主原创文章,未经博主允许不得转载。
、下半部
在中断处理过程中,不能睡眠。另外,它运行的时候,会把当前中断线在所有处理器上都屏蔽(在ack中完成屏蔽);更糟糕的情况是,如果一个处理程序是SA_INTERRUPT类型,它执行的时候会禁上所有本地中断(通过cli指令完成),所以,中断处理应该尽可能快的完成。所以Linux把中断处理分为上半部和下半部。
上半部由中断处理程序完成,它通常完成一些和硬件相关的操作,比如对中断的到达的确认。有时它还会从硬件拷贝数据,这些工作对时间非常敏感,只能靠中断处理程序自己完成。而把其它工作放到下半部实现。
下半部的执行不需要一个确切的时间,它会在稍后系统不太繁忙时执行。下半部执行的关键在于运行的时候允许响应所有的中断。最早,Linux用”bottom half”实现下半部,这种机制简称BH,但是即使属于不同的处理器,也不允许任何两个bottom half同时执行,这种机制简单,但是却有性能瓶颈。不久,又引入任务队列(task queue)机制来实现下半部,但该机制仍不够灵活,没法代替整个BH接口。
从2.3开始,内核引入软中断(softirqs)和tasklet,并完全取代了BH。.5中,BH最终舍去,在2.6中,内核用有三种机制实现下半部:软中断,tasklet和工作队列。Tasklet是基于软中断实现的。软中断可以在多个CPU上同时执行,即使它们是同一类型的,所以,软中断处理程序必须是可重入的,或者显示的用自旋锁保护相应的数据结构。而相同的tasklet不能同时在多个CPU上执行,所以tasklet不必是可重入的;但是,不同类型的tasklet可以在多个CPU上同时执行。一般来说,tasklet比较常用,它可以处理绝大部分的问题;而软中断用得比较少,但是对于时间要求较高的地方,比如网络子系统,常用软中断处理下半部工作。 4.1、软中断
内核2.6中定义了6种软中断: 下标越低,优先级越高。 4.1.、数据结构
()软中断向量
[html] view plain copy print?
//linux/interrupt.h
struct softirq_action
{
void (*action)(struct softirq_action *); //待执行的函数
void *data; //传给函数的参数
};
//kernel/softirq.c
//软中断向量数组
static struct softirq_action softirq_vec[] __cacheline_aligned_in_smp;
内核定义了一个包含32个软中断向量的数组,所以最多可有32个软中断,实际上,内核目前只使用了6个软中断。
() preempt_count字段
位于任务描述符的preempt_count是用来跟踪内核抢占和内核控制路径嵌套关键数据。其各个位的含义如下:
位 描述
—— preemption counter,内核抢占计数器(最大值255)
—— softirq counter,软中断计数器(最大值255)
—— hardirq counter,硬件中断计数器(最大值4096)
PREEMPT_ACTIVE标志 第一个计数用来表示内核抢占被关闭的次数,0表示可以抢占。第二个计数器表示推迟函数(下半部)被关闭的次数,0表示推迟函数打开。第三个计数器表示本地CPU中断嵌套的层数,irq_enter()增加该值,irq_exit减该值。
宏in_interrupt()检查current_thread_info->preempt_count的hardirq和softirq来断定是否处于中断上下文。如果这两个计数器之一为正,则返回非零。
() 软中断控制/状态结构
softirq_vec是个全局量,系统中每个CPU所看到的是同一个数组。但是,每个CPU各有其自己的“软中断控制/状态”结构,这些数据结构形成一个以CPU编号为下标的数组irq_stat[](定义在include/asm-i386/hardirq.h中)
[html] view plain copy print?
typedef struct {
unsigned int __softirq_pending;
unsigned long idle_timestamp;
unsigned int __nmi_count; /* arch dependent */
unsigned int apic_timer_irqs; /* arch dependent */
} ____cacheline_aligned irq_cpustat_t;
//位于kernel/softirq.c
irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned;
4.1.、软中断初始化
可以通过open_softirq注册软中断处理程序:
[html] view plain copy print?
<pre name="code" class="html">//位于kernel/softirq.c
//nr:软中断的索引号
// softirq_action:处理函数
//data:传递给处理函数的参数值
void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
{
softirq_vec[nr].data = data;
softirq_vec[nr].action = action;
}
//软中断初始化
void __init softirq_init(void)
{
open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
}</pre>
<pre></pre>
软中断执行时,允许响应中断,但它自己不能睡眠,4.1.、触发软中断raise_softirq会将软中断设置为挂起状态,并在下一次运行do_softirq中投入运行。
<div class="cnblogs_code"><span style="color:#008000">//</span><span style="color:#008000">位于kernel/softirq.c</span><span style="color:#008000"></span></div>
<pre name="code" class="cpp"><pre name="code" class="cpp">void fastcall raise_softirq(unsigned int nr)
{
unsigned long flags;
//保存IF值,并关中断
local_irq_save(flags); //调用wakeup_softirqd()
raise_softirq_irqoff(nr);
//恢复IF值
local_irq_restore(flags);
} inline fastcall void raise_softirq_irqoff(unsigned int nr)
{
//把软中断设置为挂起状态
__raise_softirq_irqoff(nr); //唤醒内核线程
if (!in_interrupt())
wakeup_softirqd();
</pre><br>
<pre></pre>
<pre name="code" class="cpp">该函数触发软中断前,先要关闭中断,之后再恢复;如果之前中断已经关闭,可以直接调用raise_softirq_irqoff()触发软中断。
在中断服务例程中触发软中断是最常见的形式。而中断服务例程通常作为设备驱动的一部分。例如,对于网络设备,当接口收到数据时,会产生一个中断,在中断服务例程中,最终会调用netif_rx函数处理接到的数据,而netif_rx作相应处理,最终以触发一个软中断结束处理。之后,内核在执行中断处理任务后,会调用do_softirq()。于是软中断就通过软中断处理函数去处理留给它的任务。
4.1.、软中断执行
() do_softirq()函数 //处理软中断,位于arch/i386/kernel/irq.c
asmlinkage void do_softirq(void)
{
//处于中断上下文,表明软中断是在中断上下文中触发的,或者软中断被关闭
/*这个宏限制了软中断服务例程既不能在一个硬中断服务例程内部执行,
*也不能在一个软中断服务例程内部执行(即嵌套)。但这个函数并没有对中断服务例程的执行
*进行“串行化”限制。这也就是说,不同的CPU可以同时进入对软中断服务例程的执行,每个CPU
*分别执行各自所请求的软中断服务。从这个意义上说,软中断服务例程的执行是“并发的”、多序的。
*但是,这些软中断服务例程的设计和实现必须十分小心,不能让它们相互干扰(例如通过共享的全局变量)。
*/
if (in_interrupt())
return;
//保存IF值,并关中断
local_irq_save(flags);
//调用__do_softirq
asm volatile(
" xchgl %%ebx,%%esp \n"
" call __do_softirq \n"
" movl %%ebx,%%esp \n"
: "=b"(isp)
: ""(isp)
: "memory", "cc", "edx", "ecx", "eax"
);
//恢复IF值
local_irq_restore(flags); ()__do_softirq()函数 //执行软中断,位于kernel/softirq.c
asmlinkage void __do_softirq(void)
{
struct softirq_action *h;
__u32 pending;
/*最多迭代执行10次.在执行软中断的过程中,由于允许中断,所以新的软中断可能产生.为了使推迟函数能够在
*较短的时间延迟内执行,__do_softirq会执行所有挂起的软中断,这可能会执行太长的时间而大大延迟返回用户
*空间的时间.所以,__do_softirq最多允许10次迭代.剩下的软中断在软中断内核线程ksoftirqd中处理.
*/
int max_restart = MAX_SOFTIRQ_RESTART;
int cpu; //用局部变量保存软件中断位图
pending = local_softirq_pending();
/*增加softirq计数器的值.由于执行软中断时允许中断,当do_IRQ调用irq_exit时,另一个__do_softirq实例可能
*开始执行.这是不允许的,推迟函数必须在CPU上串行执行.
*/
local_bh_disable();
cpu = smp_processor_id();
restart:
/* Reset the pending bitmask before enabling irqs */
//重置软中断位图,使得新的软中断可以发生
local_softirq_pending() = ;
//开启本地中断,执行软中断时,允许中断的发生
local_irq_enable(); h = softirq_vec; do {
if (pending & ) {
//执行软中断处理函数
h->action(h);
rcu_bh_qsctr_inc(cpu);
}
h++;
pending >>= ;
} while (pending);
//关闭中断
local_irq_disable();
//再一次检查软中断位图,因为在执行软中断处理函数时,新的软中断可能产生.
pending = local_softirq_pending();
if (pending && --max_restart)
goto restart;
/*如果还有多的软中断没有处理,通过wakeup_softirqd唤醒内核线程处理本地CPU余下的软中断.
*/
if (pending)
wakeup_softirqd();
//减softirq counter的值
__local_bh_enable();
}
()软中断执行点
内核会周期性的检查是否有挂起的软中断,它们位于内核代码的以下几个点:
()内核调用local_bh_enable()函数打开本地CPU的软中断: //位于kernel/softirq.c
void local_bh_enable(void)
{
preempt_count() -= SOFTIRQ_OFFSET - ; if (unlikely(!in_interrupt() && local_softirq_pending()))
do_softirq(); //软中断处理
//……
} </pre><br>
<br>
<pre></pre>
<pre></pre>
<pre></pre> </pre>

理解Linux中断 (3)【转】的更多相关文章

  1. 理解Linux中断 (1)【转】

    转自:http://blog.csdn.net/tommy_wxie/article/details/7425685 版权声明:本文为博主原创文章,未经博主允许不得转载. 一直认为,理解中断是理解内核 ...

  2. 理解Linux中断 (2)【转】

    转自:http://blog.csdn.net/tommy_wxie/article/details/7425692 版权声明:本文为博主原创文章,未经博主允许不得转载. .内核的中断处理 3.1.中 ...

  3. linux中断与异常

    看了<深入理解linux内核>的中断与异常,简单总结了下,如果有错误,望指正! 一 什么是中断和异常 异常又叫同步中断,是当指令执行时由cpu控制单元产生的,之所以称之为异常,是因为只有在 ...

  4. Linux中断技术、门描述符、IDT(中断描述符表)、异常控制技术总结归类

    相关学习资料 <深入理解计算机系统(原书第2版)>.pdf http://zh.wikipedia.org/zh/%E4%B8%AD%E6%96%B7 独辟蹊径品内核:Linux内核源代码 ...

  5. 理解 Linux 配置文件分类和使用

    理解 Linux 配置文件分类和使用 本文说明了 Linux 系统的配置文件,在多用户.多任务环境中,配置文件控制用户权限.系统应用程序.守护进程.服务和其它管理任务.这些任务包括管理用户帐号.分配磁 ...

  6. Linux中断管理 (1)Linux中断管理机制

    目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...

  7. Linux中断管理 (2)软中断和tasklet

    目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...

  8. Linux中断管理 (3)workqueue工作队列

    目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...

  9. 深入理解linux系统下proc文件系统内容

    深入理解linux系统下proc文件系统内容 内容摘要:Linux系统上的/proc目录是一种文件系统,即proc文件系统. Linux系统上的/proc目录是一种文件系统,即proc文件系统.与其它 ...

随机推荐

  1. Linux就这个范儿 第19章 团结就是力量 LSB是Linux标准化基地(Linux Standards Base)的简称

    Linux就这个范儿 第19章 团结就是力量  LSB是Linux标准化基地(Linux Standards Base)的简称 这个图片好可爱,它是LSB组织的图标.你肯定会问:“图标这么设计一定有说 ...

  2. php Memcache

    <?php $mem = new Memcache();//实例化一个对象 $mem->connect("localhost",11211);//连接memcache服 ...

  3. Linux环境命令大全

    java环境比较常用的几个命令: cd /  切换目录, cd ../切换到上级目录 rm -rf 文件名 删除文件 jar -xvf 文件名  解压文件 mv 文件 新路径  将当前路径下面的文件移 ...

  4. [BS] 小知识点总结-05

    [BS] 小知识点总结-05 1. 不论UIWindow的rootViewController是navC.tabBarC还是VC,也不管modalVC和rootVC中间隔着多少个VC,但是modal出 ...

  5. C# Main函数的 args参数

    网上参考 博客,使用如下代码: using System; using System.Collections.Generic; using System.Linq; using System.Text ...

  6. Java程序员面试失败的5大原因

    下面是Java程序员面试失败最有可能的5大原因,当然也许这5点原因适用于所有的程序员,所以,如果你是程序员,请认真阅读以下内容. #1 说得太少 尤其是那些开放式的问题,如“请介绍下你自己”或“请讲一 ...

  7. gcc工具链简述

    工具链软件包括BINUTILS.GCC.GLIBC.GDB等. BINUTILS是二进制程序处理工具,包括链接器.汇编器等目标程序处理的工具. GCC(GNU Compiler Collection) ...

  8. 【Linux】 JDK安装及配置 (tar.gz版)

    安装环境 Linux(Ubuntu 版) JDK安装 tar.gz为解压后就可以使用的版本,这里我将使用jdk-8u65-linux-x64.tar.gz版,安装到/usr/java/下 步骤一 将文 ...

  9. Topcoder SRM 598 div2

    e,不知道为啥进不去了,这个B题贪心,从最小和最大的匹配如果超过了就只去最大的! 然后就没了- -! 这场比赛时不知为啥,string出问题了,可能是编译器挂了!0蛋- -!

  10. Java基础(52):ClassCastException详解(转)

    ClassCastException,从字面上看,是类型转换错误,通常是进行强制类型转换时候出的错误.下面对产生ClassCastException异常的原因进行分析,然后给出这种异常的解决方法. 这 ...