本文主要是介绍为什么中断上下文不可以休眠,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
不了解2.6,但是在2.4中,中断“不能”睡眠。如果你非要在中断中睡眠,则有可能造成各种各样的问题,也可能什么事也没有。这个问题讨论了很多次,你可以在论坛中搜索“睡眠”关键字。
我这里再多说一些自己的理解:
2.4内核是非抢占式的,除非自己原意,一个进程进入内核态后不会被意外替换为另一个进程。大家都默认这样的规则,很多内核函数就可以简化设计。“在中断中睡眠”打破了这一假定,因此可能会引起不可知的问题。我说“可能”是意思是,中断睡眠不一定肯定出问题,比如当进程正在用户空间时发生这种可以睡眠的中断,我认为不会造成什么严重后果。
但是如果进程调用了一个系统调用并进入内核态时发生了这个中断,则有可能造成一些问题。
假设在中断发生前该进程正在修改某个内核数据结构,假设该结构是一个list吧,由于内核认为这个数据结构不存在几个kernel control path会同时修改的可能,就没有加同步保护。正常情况下中断结束后控制权会回来,完成剩下的操作,保证数据完整性。但如果中断睡眠了,另一个进程获得cpu,假设该新进程也恰巧要修改同一个内核数据(前面那个list),就会发生大家都了解的事情:race condition。比如要往这个list中添加一个新节点,如果不保护,后果是什么谁也说不清。
2.6我没有研究过,也许中断睡眠不再是问题了。但无论怎样,大多数实际的应用都不会在中断中获取资源,一般只会在中断中释放资源。中断是一个通知机制,通知进程应该干什么,不应该做其它的事情。也许中断也可以做更复杂的事情,我说的不过是自己的浅见。
http://linux.chinaunix.net/bbs/viewthread.php?tid=902033&extra=page%3D1%26amp%3Bfilter%3Ddigest
CU上曾经讨论过, 还不错.
看邻居帖子,大家回答的问题不大。但也有不同的回答和解释。有点乱。
有必要讨论,得出固定的结论。
确实,大家说了很多,有些地方还是不是很清楚。
希望高手们能给出正解
看邻居帖子,大家回答的问题不大。但也有不同的回答和解释。有点乱。
有必要讨论,得出固定的结论。
其实这只是一个设计上的问题, 而并不是强制的. 只是针对Linux内核而言, 这是规矩.
LKD2上面说, 切换出去之后, 何时才能调度回来? 就是中断回来之后可能不会回到之前所依俯的那个进程了.
中断不能睡眠的的最大好处就是可以简化内核的设计. 如果说中断随时可以睡眠的话, 那么就必须考虑很多其它方面的事情, 比如睡眠之后又出现了
同一IRQ号的中断又该怎么办, 等等.
其实, 如果自己能把握好, 中断中睡眠也是可以的. 但是必须能够保证这段代码具有足够的安全性与可靠性.
这是我的理解.
呵呵,我最喜欢这种讨论了。先来献丑了,说说我的看法。
先把中断处理流程给出来
- 1.进入中断处理程序--->2.保存关键上下文---->3.开中断(sti指令)--->4.进入中断处理程序的handler--->5.关中断(cli指令)---->6.写EOI寄存器(表示中断处理完成)---->7.开中断。
硬中断:
对应于上图的1、2、3步骤,在这几个步骤中,所有中断是被屏蔽的,如果在这个时候睡眠了,操作系统不会收到任何中断(包括时钟中断),系统就基本处于瘫痪状态(例如调度器依赖的时钟节拍没有等等……)
软中断:
对应上图的4(当然,准确的说应该是4步骤的后面一点,先把话说保险点,免得思一克又开始较真 )。这个时候不能睡眠的关键是因为上下文。
大家知道操作系统以进程调度为单位,进程的运行在进程的上下文中,以进程描述符作为管理的数据结构。进程可以睡眠的原因是操作系统可以切换不同进程的上下文,进行调度操作,这些操作都以进程描述符为支持。
中断运行在中断上下文,没有一个所谓的中断描述符来描述它,它不是操作系统调度的单位。一旦在中断上下文中睡眠,首先无法切换上下文(因为没有中断描述符,当前上下文的状态得不到保存),其次,没有人来唤醒它,因为它不是操作系统的调度单位。
此外,中断的发生是非常非常频繁的,在一个中断睡眠期间,其它中断发生并睡眠了,那很容易就造成中断栈溢出导致系统崩溃。
如果上述条件满足了(也就是有中断描述符,并成为调度器的调度单位,栈也不溢出了,理论上是可以做到中断睡眠的),中断是可以睡眠的,但会引起很多问题.例如,你在时钟中断中睡眠了,那操作系统的时钟就乱了,调度器也了失去依据;例如,你在一个IPI(处理器间中断)中,其它CPU都在死循环等你答复,你确睡眠了,那其它处理器也不工作了;例如,你在一个DMA中断中睡眠了,上面的进程还在同步的等待I/O的完成,性能就大大降低了……还可以举出很多例子。所以,中断是一种紧急事务,需要操作系统立即处理,不是不能做到睡眠,是它没有理由睡眠。
好了,罗嗦了一大堆,大家见仁见智,不要骂人就好。
那么LINUX有在中断中睡眠的地方吗
据我所知没有。但有没有人在他自己写的驱动程序的中断处理handler中睡眠就不知道了
也可以从优先级角度来理解。任何进程,不论其优先级多高,也不能高过isr,所以不能剥夺isr对cpu的占有权去运行进程
任何os,不管是分时os,还是实时os,不管是微内核,还是巨内核,在ISR中都不能进行进程切换。因为ISR不属于任何进程,而切换只能发生在进程上下文中。虽然ISR在执行过程中要使用进程的系统堆栈,但那只是借用, ...
呵呵,Solaris的低优先级中断是可以睡眠的,时钟中断也可以睡眠。尽管系统会尽量保证中断线程不去睡眠。例如,磁盘驱动的ISR里使用DRIVEDR mutex, 实际上系统把它当作自适应锁,当获取锁失败时,它先看其它处理器上有没有锁的拥有者在运行,如果有,就SPIN,没有就去睡眠,睡眠前,会把打断的内核线程恢复运行,保存自己的上下文。
呵呵,我最喜欢这种讨论了。先来献丑了,说说我的看法。
先把中断处理流程给出来
1.进入中断处理程序--->2.保存关键上下文---->3.开中断(sti指令)--->4.进入中断处理程序的handler--->5.关中 ...
写得很好。赞一个。
不过中断睡眠与否只是设计上的问题,不同的系统是不一样的设计。
看看我自己机器上注册的ISR, IPL是10以下的都可以睡眠,里面包括了显卡,磁盘,网卡的常见外设的中断处理:
bash-3.00# mdb -k
Loading modules: [ unix genunix specfs dtrace uppc pcplusmp scsi_vhci ufs ip hook neti sctp arp usba uhci nca lofs zfs random audiosup sppp crypto ptm ipc ]
> ::interrupts
IRQ Vect IPL Bus Trg Type CPU Share APIC/INT# ISR(s)
1 0x41 5 ISA Edg Fixed 0 1 0x0/0x1 i8042_intr
6 0x44 5 ISA Edg Fixed 0 1 0x0/0x6 fdc_intr
9 0x81 9 PCI Lvl Fixed 0 1 0x0/0x9 acpi_wrapper_isr
12 0x42 5 ISA Edg Fixed 0 1 0x0/0xc i8042_intr
14 0x40 5 ISA Edg Fixed 0 1 0x0/0xe ata_intr
15 0x43 5 ISA Edg Fixed 0 1 0x0/0xf ata_intr
16 0x82 9 PCI Lvl Fixed 0 1 0x0/0x10 nv_intr
21 0x20 1 PCI Lvl Fixed 0 4 0x0/0x15 uhci_intr, uhci_intr, uhci_intr, ehci_intr
22 0x83 9 PCI Lvl Fixed 0 1 0x0/0x16 audiovia823x_intr
23 0x60 6 PCI Lvl Fixed 0 1 0x0/0x17 gem_gld_intr
208 0xd0 14 Edg IPI all 1 - kcpc_hw_overflow_intr
209 0xd1 14 Edg IPI all 1 - cbe_fire
224 0xe0 15 Edg IPI all 1 - apic_error_intr
呵呵,我最喜欢这种讨论了。先来献丑了,说说我的看法。
先把中断处理流程给出来
1.进入中断处理程序--->2.保存关键上下文---->3.开中断(sti指令)--->4.进入中断处理程序的handler--->5.关中 ...
我觉得主要是调度的问题,引入中断线程问题就基本解决了。
前面有人说“被中断的进程和中断本身无关系”是不能睡眠的原因。我不理解,觉得说法不对。
LINUX上中断中不能睡眠(调用schedule,直接或间接)和“被中断的进程和中断本身无关系”无关。
前面有人说“被中断的进程和中断本身无关系”是不能睡眠的原因。我不理解,觉得说法不对。
这没什么不对,中断和自陷在执行的路径上,没有丝毫不同。如果说什么“中断是因为没有进程上下文,只有中断上下文”而不能睡眠的话;那么自陷同样“没有进程上下文,只有自陷上下文”。
但是自陷却可以睡眠,最明显的就是缺页异常,睡眠再正常不过了。就是因为当前发生的异常和当前进程有关系,把当前进程睡眠掉并不冤枉它。
呵呵,Solaris的低优先级中断是可以睡眠的,时钟中断也可以睡眠。尽管系统会尽量保证中断线程不去睡眠。例如,磁盘驱动的ISR里使用DRIVEDR mutex, 实际上系统把它当作自适应锁,当获取锁失败时,它先看其 ...
ISR(interrupt service routine)是不能睡眠的,我觉得你说的那个不是ISR,是IST(interrupt service thread).IST平时处于睡眠态,发生中断后,cpu执行ISR,在ISR中唤醒IST,中断服务的主体在IST中完成。引入IST后,一来可以减小内核体积,二来可以减小不可剥夺窗口,增强调度的实时性。WIN CE就是这样做的。不知Solaris的做法是否与此类似。请Solaris12兄指教
呵呵,Solaris的低优先级中断是可以睡眠的,时钟中断也可以睡眠。尽管系统会尽量保证中断线程不去睡眠。例如,磁盘驱动的ISR里使用DRIVEDR mutex, 实际上系统把它当作自适应锁,当获取锁失败时,它先看其 ...
退一万步说,假如中断可以睡眠,那么也决不是低优先级中断可以睡眠;而是当前进程为低优先级进程时能睡眠。不然那些进程调度算法不白写了?高优先级的进程有什么用?只要碰到个低优先级中断就被调度出去了。
虽然我不知道Solaris长的什么摸样。
TRAP,相当于一个软中断(INT 1, INT 3, 断点,单步等),和软中断调用的系统调用(INT 21, INT 80)几乎一样,属于当前进程,进入内核使用进程的内核栈。唯一不同的是,系统调用的软中断在用户程序中的位置相对固定,而TRAP相对不固定。
假定INT 0是被0除TRAP,你在USER中执行A = 1/0和执行INT 0是一样的,而INT 0 和INT 80也是一样的。用户程序执行INT 80有进程CONTEXT, 执行INT 0也一样有进程CONTEXT.
可以看出,TRAP(比如INT 0)的PROCESS CONTEXT和执行系统调用INT 80后的PROCESS CONTEXT是一样的。所以TRAP中如果睡眠了,是可以回来的。
而中断没有进程上下文。调度后无法回来.
如果不想回来了, 中断中也是可以睡眠的.
正因为TRAP和中断有如此不同,LINUX系统中才对于INTERRUPT 和 EXCEPTION的处理才是非常不同。
我理解的前面的说的中断和进程无关大概就是这个意思(?)
ISR(interrupt service routine)是不能睡眠的,我觉得你说的那个不是ISR,是IST(interrupt service thread).IST平时处于睡眠态,发生中断后,cpu执行ISR,在ISR中唤醒IST,中断服务的主体在IST中完成。引入IST后,一来可以减小内核体积,二来可以减小不可剥夺窗口,增强调度的实时性。WIN CE就是这样做的。不知Solaris的做法是否与此类似。请Solaris12兄指教
Cool!
你说的很准确。的确是你说的情况。
举例来说, 写网卡驱动程序,我们通常把中断服务函数说成ISR。
但在Solaris里,每个级低优先级中断都有个IST,中断服务线程。
我说的ISR是驱动程序的中断服务函数,即下面的e1000g`e1000g_intr,而你说的是下面调用栈里的_interrupt。
具体机制和你说的一样,下面的调用栈是我观察网卡驱动e1000g调用栈得到的:
[6]> ffffff001ddabc80::threadlist -v
ADDR PROC LWP CLS PRI WCHAN
ffffff001ddabc80 fffffffffbc24b30 fffffffec8551170 0 165 0
PC: thread_start THREAD: thread_create_intr()
stack pointer for thread ffffff001ddabc80: ffffff001ddabbc0
e1000g`e1000g_intr+8(2)
av_dispatch_autovect+0x78()
dispatch_hardint+0x2f()
switch_sp_and_call+0x13()
do_interrupt+0xa0()
_interrupt+0xba()
这篇关于为什么中断上下文不可以休眠的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!