




已阅读5页,还剩17页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第六章 Linux 内核的 Softirq 机制 By 詹荣开 NUDT Copyright 2003 by 詹荣开 E mail zhanrk Linux 2 4 0 Version 1 0 0 2003 2 14 摘要 本文主要从内核实现的角度分析了 Linux 2 4 0 内核的 Softirq 机制 本文是为那些想要了解 Linux I O 子系统的读者和 Linux 驱动程序开发人员而 写的 关键词 Linux Softirq 软中断 Bottom half 设备驱动程序 申明 这份文档是按照自由软件开放源代码的精神发布的 任何人可以免费获 得 使用和重新发布 但是你没有限制别人重新发布你发布内容的权利 发布 本文的目的是希望它能对读者有用 但没有任何担保 甚至没有适合特定目的 的隐含的担保 更详细的情况请参阅 GNU 通用公共许可证 GPL 以及 GNU 自由 文档协议 GFDL 你应该已经和文档一起收到一份 GNU 通用公共许可证 GPL 的副本 如果还没有 写信给 The Free Software Foundation Inc 675 Mass Ave Cambridge MA02139 USA 欢迎各位指出文档中的错误与疑问 前言 中断服务程序往往都是在 CPU 关中断的条件下执行的 以避免中断嵌套而使控 制复杂化 但是 CPU 关中断的时间不能太长 否则容易丢失中断信号 为此 Linux 将中断服务程序一分为二 各称作 Top Half 和 Bottom Half 前 者通常对时间要求较为严格 必须在中断请求发生后立即或至少在一定的时间 限制内完成 因此为了保证这种处理能原子地完成 Top Half 通常是在 CPU 关 中断的条件下执行的 具体地说 Top Half 的范围包括 从在 IDT 中登记的中 断入口函数一直到驱动程序注册在中断服务队列中的 ISR 而 Bottom Half 则 是 Top Half 根据需要来调度执行的 这些操作允许延迟到稍后执行 它的时间 要求并不严格 因此它通常是在 CPU 开中断的条件下执行的 但是 Linux 的这种 Bottom Half 以下简称 BH 机制有两个缺点 也即 1 在任意一时刻 系统只能有一个 CPU 可以执行 Bottom Half 代码 以防止 两个或多个 CPU 同时来执行 Bottom Half 函数而相互干扰 因此 BH 代码的执行 是严格 串行化 的 2 BH 函数不允许嵌套 这两个缺点在单 CPU 系统中是无关紧要的 但在 SMP 系统中却是非常致命的 因为 BH 机制的严格串行化执行显然没有充分利用 SMP 系统的多 CPU 特点 为此 Linux2 4 内核在 BH 机制的基础上进行了扩展 这就是所谓的 软中断请求 softirq 机制 6 1 软中断请求机制 Linux 的 softirq 机制是与 SMP 紧密不可分的 为此 整个 softirq 机制的设 计与实现中自始自终都贯彻了一个思想 谁触发 谁执行 Who marks Who runs 也即触发软中断的那个 CPU 负责执行它所触发的软 中断 而且每个 CPU 都由它自己的软中断触发与控制机制 这个设计思想也使 得 softirq 机制充分利用了 SMP 系统的性能和特点 6 1 1 软中断描述符 Linux 在 include linux interrupt h 头文件中定义了数据结构 softirq action 来描述一个软中断请求 如下所示 softirq mask and active fields moved to irq cpustat t in asm hardirq h to get better cache usage KAO struct softirq action void action struct softirq action void data 其中 函数指针 action 指向软中断请求的服务函数 而指针 data 则指向由服 务函数自行解释的数据 基于上述软中断描述符 Linux 在 kernel softirq c 文件中定义了一个全局的 softirq vec 32 数组 static struct softirq action softirq vec 32 cacheline aligned 在这里系统一共定义了 32 个软中断请求描述符 软中断向量 i 0 i 31 所 对应的软中断请求描述符就是 softirq vec i 这个数组是个系统全局数组 也即它被所有的 CPU 所共享 这里需要注意的一点是 每个 CPU 虽然都由它自 己的触发和控制机制 并且只执行他自己所触发的软中断请求 但是各个 CPU 所执行的软中断服务例程却是相同的 也即都是执行 softirq vec 数组中 定义的软中断服务函数 6 1 2 软中断触发机制 要实现 谁触发 谁执行 的思想 就必须为每个 CPU 都定义它自己的触发和 控制变量 为此 Linux 在 include asm i386 hardirq h 头文件中定义了数据 结构 irq cpustat t 来描述一个 CPU 的中断统计信息 其中就有用于触发和控 制软中断的成员变量 数据结构 irq cpustat t 的定义如下 entry S is sensitive to the offsets of these fields typedef struct unsigned int softirq active unsigned int softirq mask unsigned int local irq count unsigned int local bh count unsigned int syscall count unsigned int nmi count arch dependent cacheline aligned irq cpustat t 结构中每一个成员都是一个 32 位的无符号整数 其中 softirq active 和 softirq mask 就是用于触发和控制软中断的成员变量 softirq active 变量 32 位的无符号整数 表示软中断向量 0 31 的状态 如果 bit i 0 i 31 为 1 则表示软中断向量 i 在某个 CPU 上已经被触 发而处于 active 状态 为 0 表示处于非活跃状态 softirq mask 变量 32 位的无符号整数 软中断向量的屏蔽掩码 如果 bit i 0 i 31 为 1 则表示使能 enable 软中断向量 i 为 0 表示该 软中断向量被禁止 disabled 根据系统中当前的 CPU 个数 由宏 NR CPUS 表示 Linux 在 kernel softirq c 文件中为每个 CPU 都定义了它自己的中断统计信息结构 如 下所示 No separate irq stat for s390 it is part of PSA if defined CONFIG ARCH S390 irq cpustat t irq stat NR CPUS endif CONFIG ARCH S390 这样 每个 CPU 都只操作它自己的中断统计信息结构 假设有一个编号为 id 的 CPU 那么它只能操作它自己的中断统计信息结构 irq stat id 0 id NR CPUS 1 从而使各 CPU 之间互不影响 这个数组在 include linux irq cpustat h 头文件中也作了原型声明 l 触发软中断请求的操作函数 函数 cpu raise softirq 用于在编号为 cpu 的处理器上触发软中断向量 nr 它通过将相应的 softirq active 成员变量中的相应位设置为 1 来实现软 中断触发 如下所示 include linux interrupt h static inline void cpu raise softirq int cpu int nr softirq active cpu 1 nr 为了保证 原子 性地完成软中断的触发过程 Linux 在 interrupt h 头文件 中对上述内联函数又作了高层封装 也即函数 raise softirq 该函数向下 通过调用 cpu raise softirq 函数来实现软中断的触发 但在调用该函数之 前 它先通过 local irq save 函数来关闭当前 CPU 的中断并保存标志寄存器 的内容 如下所示 I do not want to use atomic variables now so that cli sti static inline void raise softirq int nr unsigned long flags local irq save flags cpu raise softirq smp processor id nr local irq restore flags 6 1 3 Linux 对软中断的预定义分类 在软中断向量 0 31 中 Linux 内核仅仅使用了软中断向量 0 3 其余被留待 系统以后扩展 Linux 在头文件 include linux interrupt h 中对软中断向量 0 3 进行了预定义 PLEASE avoid to allocate new softirqs if you need not really h igh frequency threaded job scheduling For almost all the purposes tasklets are more than enough F e all serial device BHs et al should be converted to tasklets not to softirqs enum HI SOFTIRQ 0 NET TX SOFTIRQ NET RX SOFTIRQ TASKLET SOFTIRQ 其中 软中断向量 0 即 HI SOFTIRQ 用于实现高优先级的软中断 如 高优 先级的 tasklet 将在后面详细描述 软中断向量 1 和 2 则分别用于网络数 据的发送与接收 软中断向量 3 即 TASKLET SOFTIRQ 则用于实现诸如 tasklet 这样的一般性软中断 关于 tasklet 我们将在后面详细描述 NOTE Linix 内核并不鼓励一般用户扩展使用剩余的软中断向量 因为它认为 其预定义的软中断向量 HI SOFTIRQ 和 TASKLET SOFTIRQ 已经足够应付绝大多数 应用 6 1 4 软中断机制的初始化 函数 softirq init 完成 softirq 机制的初始化 该函数由内核启动例程 start kernel 所调用 函数源码如下所示 kernel softirq c void init softirq init int i for i 0 i 32 i tasklet init bh task vec i bh action i open softirq TASKLET SOFTIRQ tasklet action NULL open softirq HI SOFTIRQ tasklet hi action NULL 初始化的过程如下 1 先用一个 for 循环来初始化用于实现 BH 机制的 bh task vec 32 数组 这一点我们将在后面详细解释 2 调用 open softirq 函数开启使用软中断向量 TASKLET SOFTIRQ 和 HI SOFTIRQ 并将它们的软中断服务函数指针分别指向 tasklet action 函数 和 tasklet hi action 函数 函数 open softirq 的主要作用是初始化设 置软中断请求描述符 softirq vec nr 6 1 5 开启一个指定的软中断向量 函数 open softirq 用于开启一个指定的软中断向量 nr 也即适当地初始化软 中断向量 nr 所对应的软中断描述符 softirq vec nr 它主要做两件事情 1 初始化设置软中断向量 nr 所对应的软中断描述符 softirq vec nr 2 将所有 CPU 的软中断屏蔽掩码变量 softirq mask 中的对应位设置为 1 以使能该软中断向量 该函数的源码如下所示 kernel softirq c void open softirq int nr void action struct softirq action voi d data unsigned long flags int i spin lock irqsave softirq vec nr data data softirq vec nr action action for i 0 i NR CPUS i softirq mask i 1 action h h active 1 while active local irq disable active softirq active cpu if active local bh enable Leave with locally disabled hard irqs It is critical to close window for infinite recursion while we help local bh count it protected us Now we are defenceless return retry goto restart 结合上述源码 我们可以看出软中断服务的执行过程如下 1 调用宏 in interrupt 来检测当前 CPU 此次是否已经处于中断服务中 该宏定义在 hardirq h 请参见 5 7 节 2 调用 local bh disable 宏将当前 CPU 的中断统计信息结构中的 local bh count 成员变量加 1 表示当前 CPU 已经处在软中断服务状态 3 由于接下来要读写当前 CPU 的中断统计信息结构中的 softirq active 变量和 softirq mask 变量 因此为了保证这一个操作过程的原子性 先用 local irq disable 宏 实际上就是 cli 指令 关闭当前 CPU 的中断 4 然后 读当前 CPU 的 softirq active 变量值和 softirq mask 变量值 当某个软中断向量被触发时 即 softirq active 变量中的相应位被置 1 只有 softirq mask 变量中的相应位也为 1 时 它的软中断服务函数才能得到 执行 因此 需要将 softirq active 变量和 softirq mask 变量作一次 与 逻辑操作 5 如果 active 变量非 0 说明需要执行软中断服务函数 因此 先将当 前 CPU 的 softirq active 中的相应位清零 然后用 local irq enable 宏 实际上就是 sti 指令 打开当前 CPU 的中断 将局部变量 mask 中的相应位 清零 其目的是 让 do softirq 函数的这一次执行不对同一个软中断向量上 的再次软中断请求进行服务 而是将它留待下一次 do softirq 执行时去服务 从而使 do sottirq 函数避免陷入无休止的软中断服务中 用一个 do while 循环来根据 active 的值去执行相应的软中断服务函数 由于接下来又 要检测当前 CPU 的 softirq active 变量 因此再一次调用 local irq disable 宏关闭当前 CPU 的中断 读取当前 CPU 的 softirq active 变量的值 并将它与局部变量 mask 进行与操作 以看看是 否又有其他软中断服务被触发了 比如前面所说的那种情形 如果有的话 那就跳转到 entry 程序段 实际上是跳转到 restart 程序段 重新执行软中断 服务 如果没有的话 那么此次软中断服务过程就宣告结束 6 最后 通过 local bh enable 宏将当前 CPU 的 local bh count 变量值 减 1 表示当前 CPU 已经离开软中断服务状态 宏 local bh enable 也定义在 include asm i386 softirq h 头文件中 dreamicedreamice 回复于 回复于 2008 11 032008 11 03 11 25 4011 25 40 6 2 tasklet 机制 Tasklet 机制是一种较为特殊的软中断 Tasklet 一词的原意是 小片任务 的 意思 这里是指一小段可执行的代码 且通常以函数的形式出现 软中断向量 HI SOFTIRQ 和 TASKLET SOFTIRQ 均是用 tasklet 机制来实现的 从某种程度上讲 tasklet 机制是 Linux 内核对 BH 机制的一种扩展 在 2 4 内 核引入了 softirq 机制后 原有的 BH 机制正是通过 tasklet 机制这个桥梁来纳 入 softirq 机制的整体框架中的 正是由于这种历史的延伸关系 使得 tasklet 机制与一般意义上的软中断有所不同 而呈现出以下两个显著的特点 1 与一般的软中断不同 某一段 tasklet 代码在某个时刻只能在一个 CPU 上运 行 而不像一般的软中断服务函数 即 softirq action 结构中的 action 函数 指针 那样 在同一时刻可以被多个 CPU 并发地执行 2 与 BH 机制不同 不同的 tasklet 代码在同一时刻可以在多个 CPU 上并发地 执行 而不像 BH 机制那样必须严格地串行化执行 也即在同一时刻系统中只能 有一个 CPU 执行 BH 函数 6 2 1 tasklet 描述符 Linux 用数据结构 tasklet struct 来描述一个 tasklet 该数据结构定义在 include linux interrupt h 头文件中 如下所示 struct tasklet struct struct tasklet struct next unsigned long state atomic t count void func unsigned long unsigned long data 各成员的含义如下 1 next 指针 指向下一个 tasklet 的指针 2 state 定义了这个 tasklet 的当前状态 这一个 32 位的无符号长整数 当前只使用了 bit 1 和 bit 0 两个状态位 其中 bit 1 1 表示这个 tasklet 当前正在某个 CPU 上被执行 它仅对 SMP 系统才有意义 其作用就是 为了防止多个 CPU 同时执行一个 tasklet 的情形出现 bit 0 1 表示这个 tasklet 已经被调度去等待执行了 对这两个状态位的宏定义如下所示 interrupt h enum TASKLET STATE SCHED Tasklet is scheduled for execution TASKLET STATE RUN Tasklet is running SMP only 3 原子计数 count 对这个 tasklet 的引用计数值 NOTE 只有当 count 等 于 0 时 tasklet 代码段才能执行 也即此时 tasklet 是被使能的 如果 count 非零 则这个 tasklet 是被禁止的 任何想要执行一个 tasklet 代码段的人都 首先必须先检查其 count 成员是否为 0 4 函数指针 func 指向以函数形式表现的可执行 tasklet 代码段 5 data 函数 func 的参数 这是一个 32 位的无符号整数 其具体含义可供 func 函数自行解释 比如将其解释成一个指向某个用户自定义数据结构的地址 值 Linux 在 interrupt h 头文件中又定义了两个用来定义 tasklet struct 结构变 量的辅助宏 define DECLARE TASKLET name func data struct tasklet struct name NULL 0 ATOMIC INIT 0 func data define DECLARE TASKLET DISABLED name func data struct tasklet struct name NULL 0 ATOMIC INIT 1 func data 显然 从上述源代码可以看出 用 DECLARE TASKLET 宏定义的 tasklet 在初始 化时是被使能的 enabled 因为其 count 成员为 0 而用 DECLARE TASKLET DISABLED 宏定义的 tasklet 在初始时是被禁止的 disabled 因为其 count 等于 1 6 2 2 改变一个 tasklet 状态的操作 在这里 tasklet 状态指两个方面 1 state 成员所表示的运行状态 2 count 成员决定的使能 禁止状态 1 改变一个 tasklet 的运行状态 state 成员中的 bit 0 表示一个 tasklet 是否已被调度去等待执行 bit 1 表示一个 tasklet 是否正在某个 CPU 上执行 对于 state 变量中某位 的改变必须是一个原子操作 因此可以用定义在 include asm bitops h 头文件 中的位操作来进行 由于 bit 1 这一位 即 TASKLET STATE RUN 仅仅对于 SMP 系统才有意义 因此 Linux 在 Interrupt h 头文件中显示地定义了对 TASKLET STATE RUN 位的 操作 如下所示 ifdef CONFIG SMP define tasklet trylock t test and set bit TASKLET STATE RUN tasklet unlock wait t 函数 tasklet disable nosync 也是一个静态 inline 函数 它简单地通过原 子操作将 count 成员变量的值减 1 如下所示 interrupt h static inline void tasklet disable nosync struct tasklet struct t atomic inc 函数 tasklet enable 用于使能一个 tasklet 如下所示 interrupt h static inline void tasklet enable struct tasklet struct t atomic dec 6 2 3 tasklet 描述符的初始化与杀死 函数 tasklet init 用来初始化一个指定的 tasklet 描述符 其源码如下所示 kernel softirq c void tasklet init struct tasklet struct t void func unsigned long unsigned long data t func func t data data t state 0 atomic set 函数 tasklet kill 用来将一个已经被调度了的 tasklet 杀死 即将其恢复到 未调度的状态 其源码如下所示 kernel softirq c void tasklet kill struct tasklet struct t if in interrupt printk Attempt to kill tasklet from interrupt n while test and set bit TASKLET STATE SCHED do current policy SCHED YIELD schedule while test bit TASKLET STATE SCHED tasklet unlock wait t clear bit TASKLET STATE SCHED 6 2 4 tasklet 对列 多个 tasklet 可以通过 tasklet 描述符中的 next 成员指针链接成一个单向对列 为此 Linux 专门在头文件 include linux interrupt h 中定义了数据结构 tasklet head 来描述一个 tasklet 对列的头部指针 如下所示 struct tasklet head struct tasklet struct list attribute aligned SMP CACHE BYTES 尽管 tasklet 机制是特定于软中断向量 HI SOFTIRQ 和 TASKLET SOFTIRQ 的一种 实现 但是 tasklet 机制仍然属于 softirq 机制的整体框架范围内的 因此 它的设计与实现仍然必须坚持 谁触发 谁执行 的思想 为此 Linux 为系 统中的每一个 CPU 都定义了一个 tasklet 对列头部 来表示应该有各个 CPU 负 责执行的 tasklet 对列 如下所示 kernel softirq c struct tasklet head tasklet vec NR CPUS cacheline aligned struct tasklet head tasklet hi vec NR CPUS cacheline aligned 其中 tasklet vec 数组用于软中断向量 TASKLET SOFTIRQ 而 tasklet hi vec 数组则用于软中断向量 HI SOFTIRQ 也即 如果 CPUi 0 i NR CPUS 1 触发了软中断向量 TASKLET SOFTIRQ 那么对列 tasklet vec i 中的每一个 tasklet 都将在 CPUi 服务于软中断向量 TASKLET SOFTIRQ 时被 CPUi 所执行 同样地 如果 CPUi 0 i NR CPUS 1 触发了软中断向量 HI SOFTIRQ 那么队列 tasklet vec i 中的每一个 tasklet 都将 CPUi 在对软中断向量 HI SOFTIRQ 进行服务时被 CPUi 所执行 队列 tasklet vec I 和 tasklet hi vec I 中的各个 tasklet 是怎样被所 CPUi 所执行的呢 其关键就是软中断向量 TASKLET SOFTIRQ 和 HI SOFTIRQ 的 软中断服务程序 tasklet action 函数和 tasklet hi action 函数 下 面我们就来分析这两个函数 6 2 5 软中断向量 TASKLET SOFTIRQ 和 HI SOFTIRQ Linux 为软中断向量 TASKLET SOFTIRQ 和 HI SOFTIRQ 实现了专用的触发函数和 软中断服务函数 其中 tasklet schedule 函数和 tasklet hi schedule 函数分别用来在当前 CPU 上触发软中断向量 TASKLET SOFTIRQ 和 HI SOFTIRQ 并把指定的 tasklet 加入当前 CPU 所对应的 tasklet 队列中去等待执行 而 tasklet action 函数和 tasklet hi action 函数则分别是软中断向量 TASKLET SOFTIRQ 和 HI SOFTIRQ 的软中断服务函数 在初始化函数 softirq init 中 这两个软中断向量对应的描述符 softirq vec 0 和 softirq vec 3 中的 action 函数指针就被分别初始化成指向函数 tasklet hi action 和函数 tasklet action 1 软中断向量 TASKLET SOFTIRQ 的触发函数 tasklet schedule 该函数实现在 include linux interrupt h 头文件中 是一个 inline 函数 其 源码如下所示 static inline void tasklet schedule struct tasklet struct t if test and set bit TASKLET STATE SCHED unsigned long flags local irq save flags t next tasklet vec cpu list tasklet vec cpu list t cpu raise softirq cpu TASKLET SOFTIRQ local irq restore flags 该函数的参数 t 指向要在当前 CPU 上被执行的 tasklet 对该函数的 NOTE 如下 调用 test and set bit 函数将待调度的 tasklet 的 state 成员变量的 bit 0 位 也即 TASKLET STATE SCHED 位 设置为 1 该函数同时还返回 TASKLET STATE SCHED 位的原有值 因此如果 bit 0 为的原有值已经为 1 那就说明这个 tasklet 已经被调度到另一个 CPU 上去等待执行了 由于一个 tasklet 在某一个时刻只能由一个 CPU 来执行 因此 tasklet schedule 函数 什么也不做就直接返回了 否则 就继续下面的调度操作 首先 调用 local irq save 函数来关闭当前 CPU 的中断 以保证下面的步 骤在当前 CPU 上原子地被执行 然后 将待调度的 tasklet 添加到当前 CPU 对应的 tasklet 队列的首部 接着 调用 cpu raise softirq 函数在当前 CPU 上触发软中断请求 TASKLET SOFTIRQ 最后 调用 local irq restore 函数来开当前 CPU 的中断 2 软中断向量 TASKLET SOFTIRQ 的服务程序 tasklet action 函数 tasklet action 是 tasklet 机制与软中断向量 TASKLET SOFTIRQ 的联系 纽带 正是该函数将当前 CPU 的 tasklet 队列中的各个 tasklet 放到当前 CPU 上来执行的 该函数实现在 kernel softirq c 文件中 其源代码如下 static void tasklet action struct softirq action a int cpu smp processor id struct tasklet struct list local irq disable list tasklet vec cpu list tasklet vec cpu list NULL local irq enable while list NULL struct tasklet struct t list list list next if tasklet trylock t if atomic read t func t data talklet trylock uses test and set bit that imply an mb when it returns zero thus we need the explicit mb only here while closing the critical section ifdef CONFIG SMP smp mb before clear bit endif tasklet unlock t continue tasklet unlock t local irq disable t next tasklet vec cpu list tasklet vec cpu list t cpu raise softirq cpu TASKLET SOFTIRQ local irq enable 注释如下 首先 在当前 CPU 关中断的情况下 原子 地读取当前 CPU 的 tasklet 队 列头部指针 将其保存到局部变量 list 指针中 然后将当前 CPU 的 tasklet 队 列头部指针设置为 NULL 以表示理论上当前 CPU 将不再有 tasklet 需要执行 但最后的实际结果却并不一定如此 下面将会看到 然后 用一个 while 循环来遍历由 list 所指向的 tasklet 队列 队列中的 各个元素就是将在当前 CPU 上执行的 tasklet 循环体的执行步骤如下 l 用指针 t 来表示当前队列元素 即当前需要执行的 tasklet l 更新 list 指针为 list next 使它指向下一个要执行的 tasklet l 用 tasklet trylock 宏试图对当前要执行的 tasklet 由指针 t 所指向 进 行加锁 如果加锁成功 当前没有任何其他 CPU 正在执行这个 tasklet 则 用原子读函数 atomic read 进一步判断 count 成员的值 如果 count 为 0 说 明这个 tasklet 是允许执行的 于是 1 先清除 TASKLET STATE SCHED 位 2 然后 调用这个 tasklet 的可执行函数 func 3 执行 barrier 操作 4 调用宏 tasklet unlock 来清除 TASKLET STATE RUN 位 5 最后 执 行 continue 语句跳过下面的步骤 回到 while 循环继续遍历队列中的下一个元 素 如果 count 不为 0 说明这个 tasklet 是禁止运行的 于是调用 tasklet unlock 清除前面用 tasklet trylock 设置的 TASKLET STATE RUN 位 l 如果 tasklet trylock 加锁不成功 或者因为当前 tasklet 的 count 值非 0 而不允许执行时 我们必须将这个 tasklet 重新放回到当前 CPU 的 tasklet 队列中 以留待这个 CPU 下次服务软中断向量 TASKLET SOFTIRQ 时再执行 为 此进行这样几步操作 1 先关 CPU 中断 以保证下面操作的原子性 2 把这个 tasklet 重新放回到当前 CPU 的 tasklet 队列的首部 3 调用 cpu raise softirq 函数在当前 CPU 上再触发一次软中断请求 TASKLET SOFTIRQ 4 开中断 l 最后 回到 while 循环继续遍历队列 3 软中断向量 HI SOFTIRQ 的触发函数 tasklet hi schedule 该函数与 tasklet schedule 几乎相同 其源码如下 include linux interrupt h static inline void tasklet hi schedule struct tasklet struct t if test and set bit TASKLET STATE SCHED unsigned long flags local irq save flags t next tasklet hi vec cpu list tasklet hi vec cpu list t cpu raise softirq cpu HI SOFTIRQ local irq restore flags 4 软中断向量 HI SOFTIRQ 的服务函数 tasklet hi action 该函数与 tasklet action 函数几乎相同 其源码如下 kernel softirq c static void tasklet hi action struct softirq action a int cpu smp processor id struct tasklet struct list local irq disable list tasklet hi vec cpu list tasklet hi vec cpu list NULL local irq enable while list NULL struct tasklet struct t list list list next if tasklet trylock t if atomic read t func t data tasklet unlock t continue tasklet unlock t local irq disable t next tasklet hi vec cpu list tasklet hi vec cpu list t cpu raise softirq cpu HI SOFTIRQ local irq enable dreamicedreamice 回复于 回复于 2008 11 032008 11 03 11 26 1911 26 19 3 Bottom Half 机制 Bottom Half 机制在新的 softirq 机制中被保留下来 并作为 softirq 框架的 一部分 其实现也似乎更为复杂些 因为它是通过 tasklet 机制这个中介桥梁 来纳入 softirq 框架中的 实际上 软中断向量 HI SOFTIRQ 是内核专用于执行 BH 函数的 6 3 1 数据结构的定义 原有的 32 个 BH 函数指针被保留 定义在 kernel softirq c 文件中 static void bh base 32 void 但是 每个 BH 函数都对应有一个 tasklet 并由 tasklet 的可执行函数 func 来负责调用相应的 bh 函数 func 函数的参数指定调用哪一个 BH 函数 与 32 个 BH 函数指针相对应的 tasklet 的定义如下所示 kernel softirq c struct tasklet struct bh task vec 32 上述 tasklet 数组使系统全局的 它对所有的 CPU 均可见 由于在某一个时刻 只能有一个 CPU 在执行 BH 函数 因此定义一个全局的自旋锁来保护 BH 函数 如下所示 kernel softirq c spinlock t global bh lock SPIN LOCK UNLOCKED 6 3 2 初始化 在 softirq 机制的初始化函数 softirq init 中将 bh task vec 32 数组中 的每一个 tasklet 中的 func 函数指针都设置为指
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 硬件形式化方法-洞察及研究
- 肥儿散干预机制解析-洞察及研究
- 中学生应当具备的感恩品质
- 个人账户开户手续
- 改善血液循环的按摩规范
- 北京地区可吸入颗粒物污染特征与边界层气象因子的深度剖析
- 分数阶变分PDE:开启图像建模与去噪算法的新篇章
- WiMAX无线网络安全接入技术:原理、挑战与应对策略研究
- 智能电网规划设计-洞察及研究
- 智能农业气象信息服务-洞察及研究
- 《矿区水文地质工程地质勘探规范》水文地质单元及侵蚀基准面划分的探讨
- 高等计算机系统结构课件
- 低血压的护理和处理课件
- 海南自贸港测试题库(195道)
- 我的家乡威海荣成宣传介绍课件
- 仪器维护、保养记录表
- 结婚函调报告表(带参考)
- 管理学原理课程教学大纲
- 指针式万用表的使用方法课件
- 国家电网有限公司营销现场作业安全工作规程
- 小学数学植树问题-课件
评论
0/150
提交评论