Linux内核之旅-中断处理的软中断

24 篇文章 1 订阅
24 篇文章 3 订阅

前言

  • 中断处理程序机制局限性,它只能作为中断处理流程的“上半部”
    1,中断随时都会发生,它会以异步方式执行。
    2,中断处理程序要尽快地执行完(要它完成的工作越少越好),首先、它通常需要对硬件进行操作,这本身带来了时限要求,第二、其他中断都会被屏蔽,这直接影响了操作系统和硬件的通信,中断被屏蔽的时间会极大的影响系统的响应能力和性能。最后、它不再进程上下文中,不能被阻塞。

  • 该如何分配中断处理的任务是在“上半部”还是“下半部”?
    1,

软中断

目前,只有两个子系统(网络和SCSI)直接使用软中断。

相关数据结构设计

<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
{
	v*oid	(*action)(struct softirq_action *);
};

kernel/softirq.c 定义包含32个软中断的该结构数组

static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;

相关服务接口(操作接口)设计

1,软中段处理程序:

void (*softirq_hander)(struct softirq_action *)

2,软中段处理的核心部分:
2.1,软中断核心处理函数do_softirq
先检查软中断重入条件:必须不在硬中断里并且不在软中断里,符合条件之后就可以开始做如下的软中断处理了:

pending = local_softirq_pending();
if (pending)
    __do_softirq();

这个处理是在关中断的保护下完成的,毕竟软中断和硬中断本质上是一样的,都是中断体系的(当然,进入到硬/软中断内部再开则另当别论了)。也可以看到,局部变量pending没有传入__do_softirq内部,所以此处仅是判断,不是使用,此处判断值和内部使用值可能有差异,位图中置位位数会少一些。
我们再深究一下这个检查条件。我们的理解是:
这个条件达到了两个效果:同一个cpu上的软中断不嵌套;嵌套硬中断中不处理软中断。就同一个cpu而言,__do_softirq函数的执行是串行的,非重入的(do_softirq函数可以说是可重入的);就多个cpu而言,__do_softirq函数是可重入的,即使是同一个类型的软中断。也就是说,软中断通过这个检查条件做到了本cpu上的软中断处理串行化,当然,多cpu之间的还是并行的,所以同一类型软中断处理还是需要保护自己的相关共享数据结构的。

2.2, 软中断核心函数处理之__do_softirq
__do_softirq函数处理是尽量(虽然可能还是执行不完)执行所有被激活的软中断(由本cpu上的__softirq_pending位图标识)处理。我们分三个阶段分析。
准备处理阶段:关闭软中断(效果是让上面提到的检查条件为真,从而达到禁止本cpu上的软中断嵌套的目的)。
核心处理阶段:关硬中断,获得本cpu的__softirq_pending位图并存储起来,清空位图,开硬中断(仅在读写位图时需要关硬中断,防止其它硬中断同时操作)。执行本cpu的所有软中断(由存储起来的位图获得)。这个核心处理是个循环,最多10次(MAX_SOFTIRQ_RESTART),毕竟此时用的是用户进程的栈,不能借用太久。退出循环的条件是:总时间超出或者被抢占(开中断就会有被抢占)或者达到10次了。
结尾处理阶段:关硬中断,开软中断。

另外,如果10次循环都解决不完软中断,说明期间发生的硬中断很多,带来的额外的软中断也很多。那么就不继续影响借用的用户进程栈了,直接交给专门的ksoftirqd内核线程处理。这也就说明了循环的含义:处理软中断期间时还会进入新的硬中断,从而带进新的软中断(当然,仅仅是在本cpu的__softirq_pending上置位,不会有实际处理),所以需要反复去处理(处理的目标很明确,就是要清空本cpu上的__softirq_pending位图)。

再看看那个防止软中断嵌套的流程。关软中断中肯定有一句原子地加1的关键语句,如果当前内核路径A在该原子操作之前被另一个内核路径B打断,则B执行完硬中断和软中断后,返回到A的此处,A接着执行该原子操作,之后的软中断处理应该是空转,因为肯定已经被B处理完了。如果在该原子操作之后被B打断,则B执行完硬中断,不会执行自己的软中断而是会直接退出(因为软中断嵌套了),返回到A的此处,A接着执行,这次A除了处理自己软中断,还会额外地处理B的软中断。

对于preempt_count中的软中断位,由上述可以知道,它的作用有两个:防止软中断在单cpu上嵌套;保证了在执行软中断期间不被抢占。

最后,还得重复一句:这里讲的__do_softirq函数都是在一个cpu上的处理,多个cpu上的并行是不受任何控制的。

3,分配索引
软中断目前有10(由NR_SOFTIRQS定义)个,通过softirq_vec[NR_SOFTIRQS]数组来管理这些软中断,全部cpu共用。

/* PLEASE, avoid to allocate new softirqs, if you need not _really_ high
   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,
	TIMER_SOFTIRQ,
	NET_TX_SOFTIRQ,
	NET_RX_SOFTIRQ,
	BLOCK_SOFTIRQ,
	BLOCK_IOPOLL_SOFTIRQ,
	TASKLET_SOFTIRQ,
	SCHED_SOFTIRQ,
	HRTIMER_SOFTIRQ,
	RCU_SOFTIRQ,	/* Preferable RCU should always be the last softirq */

	NR_SOFTIRQS
};

4,注册你的中断处理程序
通过open_softirq()将具体的软中断处理函数和软中断编号绑定。如网络系统注册了收发包的软中断处理函数:

open_softirq(NET_TX_SOFTIRQ, net_tx_action);
open_softirq(NET_RX_SOFTIRQ, net_rx_action);

5,触发你的软中断

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值