内核中断异常抢占总结篇Word文档下载推荐.docx
- 文档编号:21356738
- 上传时间:2023-01-29
- 格式:DOCX
- 页数:18
- 大小:26.21KB
内核中断异常抢占总结篇Word文档下载推荐.docx
《内核中断异常抢占总结篇Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《内核中断异常抢占总结篇Word文档下载推荐.docx(18页珍藏版)》请在冰豆网上搜索。
硬中断和软中断(只要是中断上下文)执行的时候都不允许内核抢占,换句话说,中断上下文中永远不允许进程切换。
(个人理解,由于中断处理程序都需要较快地完成,而且中断处理程序可以嵌套,因此中断处理程序必须不能阻塞,否则性能就非常不能保证了。
)
三、用户抢占和内核抢占
抢占分两种情况:
用户抢占和内核抢占,其中内核抢占在Linux2.5.4版本发布时被并入内核的,通SMP一样作为内核的一项标准可选配置。
1、用户抢占:
内核即将返回用户空间的时候,如果needresched标志被设置,会导致schedule()被调用,此时就会发生用户抢占。
在内核返回用户空间的时候,它知道自己是安全的。
所以,内核无论是在从中断处理程序还是在系统调用后返回,都会检查needresched标志。
如果它被设置了,那么,内核会选择一个其他(更合适的)进程投入运行。
在内核抢占还没有出现的时候,内核所有的抢占情况都是用户抢占。
2、内核抢占:
内核抢占是指,一个在内核态运行的进程,可能在执行内核函数期间被另一个进程取代。
不是在内核的任何一个地方都可以发生内核抢占的。
内核不能被抢占的情况如下:
1)内核正进行中断处理。
在Linux内核中进程不能抢占中断(中断只能被其他中断中止、抢占,进程不能中止、抢占中断),在中断例程中不允许进行进程调度。
进程调度函数schedule()会对此作出判断,如果是在中断中调用,会打印出错信息。
2)内核正在进行中断上下文的BottomHalf(中断的底半部)处理。
硬件中断返回前会执行软中断,此时仍然处于中断上下文中。
3)内核的代码段正持有spinlock自旋锁、writelock/readlock读写锁等锁,处干这些锁的保护状态中。
内核中的这些锁是为了在SMP系统中短时间内保证不同CPU上运行的进程并发执行的正确性。
当持有这些锁时,内核不应该被抢占。
4)内核正在执行调度程序Scheduler。
抢占的原因就是为了进行新的调度,没有理由将调度程序抢占掉再运行调度程序。
5)内核正在对每个CPU“私有”的数据结构操作(Per-CPUdatestructures)。
在SMP中,对于per-CPU数据结构未用spinlocks保护,因为这些数据结构隐含地被保护了(不同的CPU有不一样的per-CPU数据,其他CPU上运行的进程不会用到另一个CPU的per-CPU数据)。
但是如果允许抢占,但一个进程被抢占后重新调度,有可能调度到其他的CPU上去,这时定义的Per-CPU变量就会有问题,这时应禁抢占。
除了上述情况,在内核的任何地方都可能发生内核抢占,内核抢占发生的时机一般在:
1)当从中断处理程序正在执行,且返回内核空间之前。
2)当内核代码再一次具有可抢占性的时候,如解锁(spin_unlock_bh)及使能软中断(local_bh_enable)等。
3)如果内核中的任务显式的调用schedule()。
4)如果内核中的任务阻塞(这同样也会导致调用schedule())。
内核抢占主要是为实时系统来设计的,但也不是在所有情况下都是最优的,因为抢占也需要调度和同步开销,在某些情况下甚至要关闭内核抢占。
以下是一篇关于开启和关闭内核抢占性能测试的文章。
四、怎么对内核临界区进行保护
在进程内核数据结构的互斥同步访问时,我们最常用的办法是:
信号量(睡眠等待),自旋锁(自旋等待),中断禁止和软中断禁止。
往往需要几种方法配合使用才能达到我们想要的结果。
1、保护异常(最典型的是系统调用)所访问的数据结构
此时最常选用的是信号量,因为信号量原语允许进程睡眠到资源变为可用,对大部分系统调用而言,这是所期望的行为。
信号量的工作方式在单处理器系统和多处理器系统上完全相同。
只有在访问每CPU变量的情况下,必须显式地禁用内核抢占,其他情况下内核抢占不会出现问题。
2、保护中断所访问的数据结构
1)单处理器情况下:
假如数据结构只被这一种中断访问,则完全可以不加同步原语,因为中断不能被同一种中断“中断”;
假如数据结构被多个中断处理程序访问,则必须通过禁用本地中断来保护临界区。
2)多处理器情况下:
除了必须禁用本地中断,还必须使用自旋锁来避免来自其他CPU的干扰。
可以使用如spin_lock_irq()来完成这两件事情。
3、保护可延迟函数(软中断和tasklet)所访问的数据结构
在单处理器系统上不存在竞争条件,因为可延迟函数的执行在一个CPU上是串行的,一个可延迟函数不会被另一个可延迟函数所中断。
因此无需同步原语。
需要自旋锁来加以保护。
由于软中断和tasklet并发程度不同,加锁情况也不同。
同一软中断可以在不同CPU上运行,因此无论一个或多个软中断,都必须用如spin_lock加以保护。
同一tasklet不能在不同CPU上运行,因此无需加锁;
不同tasklet可以在不同CPU上运行,因此也需要如spin_lock的锁加以保护。
4、保护由异常和中断访问的数据结构
单处理器情况下:
1)对中断而言:
中断不能被异常“中断”,无需考虑异常的干扰。
第1条一样,如果此数据结构只被一种中断访问,则可不加同步原语;
否则要禁用本地中断。
2)对异常而言:
异常的优先级低,如需访问共享数据结构,必须先禁用本地中断。
多处理器情况下:
除了单处理器考虑的情况外,还必须用自旋锁排除其他CPU的干扰。
5、保护由异常和可延迟函数访问的数据结构
1)对可延迟函数而言:
可延迟函数不能被异常“中断”,无需考虑异常的干扰。
在每个CPU上可延迟函数串行执行,不存在竞争条件,因此不用同步原语。
异常的优先级低,如需访问共享数据结构,必须先禁用本地软中断。
6、保护由中断和可延迟函数访问的数据机构
中断不能被可延迟函数“中断”,无需考虑可延迟函数的干扰。
2)对可延迟函数而言:
可延迟函数的优先级低,如需访问共享数据结构,必须先禁用本地中断。
除了单处理器上考虑的外,还必须用自旋锁排除其他CPU的干扰。
7、保护由异常、中断和可延迟函数访问的数据结构
优先级最高,无需考虑其他两种的影响。
3)对异常而言:
禁用了本地中断,也就相当于禁用了本地软中断。
五、软中断源码分析
之所以说软中断的执行时是串行的,是因为在软中断执行时,对于从硬中断进来的即将要执行的新的软中断会采取屏蔽措施,不让他们立即运行,而是保存起来,延迟一会,等自身的软中断执行完毕后,再执行那些保存起来的软中断,从而达到串行的目的。
[cpp]viewplaincopyprint?
1.//
2.//
do_IRQ
函数执行完硬件
ISR
后退出时调用此函数。
3.//
4.void
irq_exit(void)
5.{
6.
account_system_vtime(current);
7.
trace_hardirq_exit();
8.
sub_preempt_count(IRQ_EXIT_OFFSET);
9.
//
10.
//
判断当前是否有硬件中断嵌套,并且是否有软中断在
11.
pending
状态,注意:
这里只有两个条件同时满足
12.
时,才有可能调用
do_softirq()
进入软中断。
也就是
13.
说确认当前所有硬件中断处理完成,且有硬件中断安装了
14.
软中断处理时理时才会进入。
15.
16.
if
(!
in_interrupt()
&
local_softirq_pending())
17.
18.
其实这里就是调用
执行
19.
20.
invoke_softirq();
21.
preempt_enable_no_resched();
22.}
23.#ifndef
__ARCH_HAS_DO_SOFTIRQ
24.asmlinkage
void
do_softirq(void)
25.{
26.
__u32
pending;
27.
unsigned
long
flags;
28.
29.
这个函数判断,如果当前有硬件中断嵌套,或
30.
有软中断正在执行时候,则马上返回。
在这个
31.
入口判断主要是为了和
ksoftirqd
互斥。
32.
33.
(in_interrupt())
34.
35.
36.
关中断执行以下代码
37.
38.
local_irq_save(flags);
39.
40.
判断是否有
的软中断需要处理。
41.
42.
=
local_softirq_pending();
43.
44.
如果有则调用
__do_softirq()
进行实际处理
45.
46.
(pending)
47.
__do_softirq();
48.
49.
开中断继续执行
50.
51.
local_irq_restore(flags);
52.}
53.//
54.//
最大软中断调用次数为
10
次。
55.//
56.#define
MAX_SOFTIRQ_RESTART
10
57.asmlinkage
__do_softirq(void)
58.{
59.
60.
软件中断处理结构,此结构中包括了
中
61.
注册的回调函数。
62.
63.
struct
softirq_action
*h;
64.
65.
int
max_restart
MAX_SOFTIRQ_RESTART;
66.
cpu;
67.
68.
得到当前所有
的软中断。
69.
70.
71.
72.
73.
执行到这里要屏蔽其他软中断,这里也就证实了
74.
每个
CPU
上同时运行的软中断只能有一个。
75.
76.
__local_bh_disable((unsigned
long)__builtin_return_address(0));
77.
trace_softirq_enter();
78.
79.
针对
SMP
得到当前正在处理的
CPU
80.
81.
cpu
smp_processor_id();
82.//
83.//
循环标志
84.//
85.restart:
86.
87.
每次循环在允许硬件
强占前,首先重置软中断
88.
的标志位。
89.
90.
/*
Reset
the
bitmask
before
enabling
irqs
*/
91.
set_softirq_pending(0);
92.
93.
到这里才开中断运行,注意:
以前运行状态一直是关中断
94.
运行,这时当前处理软中断才可能被硬件中断抢占。
也就
95.
是说在进入软中断时不是一开始就会被硬件中断抢占。
只有
96.
在这里以后的代码才可能被硬件中断抢占。
97.
98.
local_irq_enable();
99.
100.
这里要注意,以下代码运行时能被硬件中断抢占,但
101.
这个硬件
执行完成后,他的所注册的软中断无法马上运行,
102.
别忘了,目前虽是开硬件中断执行,但前面的
__local_bh_disable()
103.
函数屏蔽了软中断。
所以这种环境下只能被硬件中断抢占,但这
104.
个硬中断注册的软中断回调函数无法运行。
要问为什么,那是因为
105.
__local_bh_disable()
函数设置了一个标志当作互斥量,而这个
106.
标志正是上面的
irq_exit()
和
函数中的
107.
函数判断的条件之一,也就是说
108.
函数不仅检测硬中断而且还判断了软中断。
所以在这个环境下触发
109.
硬中断时注册的软中断,根本无法重新进入到这个函数中来,只能
110.
是做一个标志,等待下面的重复循环(最大
MAX_SOFTIRQ_RESTART)
111.
才可能处理到这个时候触发的硬件中断所注册的软中断。
112.
113.
114.
得到软中断向量表。
115.
116.
h
softirq_vec;
117.
118.
循环处理所有
softirq
软中断注册函数。
119.
120.
do
{
121.
122.
如果对应的软中断设置
标志则表明
123.
需要进一步处理他所注册的函数。
124.
125.
(pending
1)
126.
127.
在这里执行了这个软中断所注册的回调函数。
128.
129.
h->
action(h);
130.
rcu_bh_qsctr_inc(cpu);
131.
}
132.
133.
继续找,直到把软中断向量表中所有
的软
134.
中断处理完成。
135.
136.
h++;
137.
138.
从代码里能看出按位操作,表明一次循环只
139.
处理
32
个软中断的回调函数。
140.
141.
>
1;
142.
while
(pending);
143.
144.
关中断执行以下代码。
注意:
这里又关中断了,下面的
145.
代码执行过程中硬件中断无法抢占。
146.
147.
local_irq_disable();
148.
149.
前面提到过,在刚才开硬件中断执行环境时只能被硬件中断
150.
抢占,在这个时候是无法处理软中断的,因为刚才开中
151.
断执行过程中可能多次被硬件中断抢占,每抢占一次就有可
152.
能注册一个软中断,所以要再重新取一次所有的软中断。
153.
以便下面的代码进行处理后跳回到
restart
处重复执行。
154.
155.
156
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 内核 中断 异常 抢占 总结