思一克 发表于 2007-06-27 09:19

关于LINUX在中断(硬软)中不能睡眠的真正原因

看邻居帖子,大家回答的问题不大。但也有不同的回答和解释。有点乱。

有必要讨论,得出固定的结论。

xiegang112 发表于 2007-06-27 09:29

确实,大家说了很多,有些地方还是不是很清楚。
希望高手们能给出正解

scutan 发表于 2007-06-27 09:38

原帖由 思一克 于 2007-6-27 09:19 发表于 1楼
看邻居帖子,大家回答的问题不大。但也有不同的回答和解释。有点乱。

有必要讨论,得出固定的结论。


其实这只是一个设计上的问题, 而并不是强制的. 只是针对Linux内核而言, 这是规矩.
LKD2上面说, 切换出去之后, 何时才能调度回来? 就是中断回来之后可能不会回到之前所依俯的那个进程了.
中断不能睡眠的的最大好处就是可以简化内核的设计. 如果说中断随时可以睡眠的话, 那么就必须考虑很多其它方面的事情, 比如睡眠之后又出现了
同一IRQ号的中断又该怎么办, 等等.
其实, 如果自己能把握好, 中断中睡眠也是可以的. 但是必须能够保证这段代码具有足够的安全性与可靠性.
这是我的理解.

zx_wing 发表于 2007-06-27 10:09

呵呵,我最喜欢这种讨论了。先来献丑了,说说我的看法。
先把中断处理流程给出来

1.进入中断处理程序--->2.保存关键上下文---->3.开中断(sti指令)--->4.进入中断处理程序的handler--->5.关中断(cli指令)---->6.写EOI寄存器(表示中断处理完成)---->7.开中断。

硬中断:
对应于上图的1、2、3步骤,在这几个步骤中,所有中断是被屏蔽的,如果在这个时候睡眠了,操作系统不会收到任何中断(包括时钟中断),系统就基本处于瘫痪状态(例如调度器依赖的时钟节拍没有等等……)

软中断:
对应上图的4(当然,准确的说应该是4步骤的后面一点,先把话说保险点,免得思一克又开始较真:lol: )。这个时候不能睡眠的关键是因为上下文。
大家知道操作系统以进程调度为单位,进程的运行在进程的上下文中,以进程描述符作为管理的数据结构。进程可以睡眠的原因是操作系统可以切换不同进程的上下文,进行调度操作,这些操作都以进程描述符为支持。
中断运行在中断上下文,没有一个所谓的中断描述符来描述它,它不是操作系统调度的单位。一旦在中断上下文中睡眠,首先无法切换上下文(因为没有中断描述符,当前上下文的状态得不到保存),其次,没有人来唤醒它,因为它不是操作系统的调度单位。
此外,中断的发生是非常非常频繁的,在一个中断睡眠期间,其它中断发生并睡眠了,那很容易就造成中断栈溢出导致系统崩溃。

如果上述条件满足了(也就是有中断描述符,并成为调度器的调度单位,栈也不溢出了,理论上是可以做到中断睡眠的),中断是可以睡眠的,但会引起很多问题.例如,你在时钟中断中睡眠了,那操作系统的时钟就乱了,调度器也了失去依据;例如,你在一个IPI(处理器间中断)中,其它CPU都在死循环等你答复,你确睡眠了,那其它处理器也不工作了;例如,你在一个DMA中断中睡眠了,上面的进程还在同步的等待I/O的完成,性能就大大降低了……还可以举出很多例子。所以,中断是一种紧急事务,需要操作系统立即处理,不是不能做到睡眠,是它没有理由睡眠。

好了,罗嗦了一大堆,大家见仁见智,不要骂人就好。

思一克 发表于 2007-06-27 10:20

zx_wing, scutan 谢谢

思一克 发表于 2007-06-27 10:21

那么LINUX有在中断中睡眠的地方吗

zx_wing 发表于 2007-06-27 10:31

原帖由 思一克 于 2007-6-27 10:21 发表于 6楼
那么LINUX有在中断中睡眠的地方吗
据我所知没有。但有没有人在他自己写的驱动程序的中断处理handler中睡眠就不知道了:lol:

gta 发表于 2007-06-27 13:29

任何os,不管是分时os,还是实时os,不管是微内核,还是巨内核,在ISR中都不能进行进程切换。因为ISR不属于任何进程,而切换只能发生在进程上下文中。虽然ISR在执行过程中要使用进程的系统堆栈,但那只是借用,堆栈并不属于isr,而是属于进程。
也可以从优先级角度来理解。任何进程,不论其优先级多高,也不能高过isr,所以不能剥夺isr对cpu的占有权去运行进程

Solaris12 发表于 2007-06-27 13:58

原帖由 gta 于 2007-6-27 13:29 发表于 8楼
任何os,不管是分时os,还是实时os,不管是微内核,还是巨内核,在ISR中都不能进行进程切换。因为ISR不属于任何进程,而切换只能发生在进程上下文中。虽然ISR在执行过程中要使用进程的系统堆栈,但那只是借用, ...


呵呵,Solaris的低优先级中断是可以睡眠的,时钟中断也可以睡眠。尽管系统会尽量保证中断线程不去睡眠。例如,磁盘驱动的ISR里使用DRIVEDR mutex, 实际上系统把它当作自适应锁,当获取锁失败时,它先看其它处理器上有没有锁的拥有者在运行,如果有,就SPIN,没有就去睡眠,睡眠前,会把打断的内核线程恢复运行,保存自己的上下文。

Solaris12 发表于 2007-06-27 14:04

原帖由 zx_wing 于 2007-6-27 10:09 发表于 4楼
呵呵,我最喜欢这种讨论了。先来献丑了,说说我的看法。
先把中断处理流程给出来

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
IRQVect IPL Bus    Trg Type   CPU Share APIC/INT# ISR(s)
1    0x41 5   ISA    Edg Fixed0   1   0x0/0x1   i8042_intr
6    0x44 5   ISA    Edg Fixed0   1   0x0/0x6   fdc_intr
9    0x81 9   PCI    Lvl Fixed0   1   0x0/0x9   acpi_wrapper_isr
12   0x42 5   ISA    Edg Fixed0   1   0x0/0xc   i8042_intr
14   0x40 5   ISA    Edg Fixed0   1   0x0/0xe   ata_intr
15   0x43 5   ISA    Edg Fixed0   1   0x0/0xf   ata_intr
16   0x82 9   PCI    Lvl Fixed0   1   0x0/0x10nv_intr
21   0x20 1   PCI    Lvl Fixed0   4   0x0/0x15uhci_intr, uhci_intr, uhci_intr, ehci_intr
22   0x83 9   PCI    Lvl Fixed0   1   0x0/0x16audiovia823x_intr
23   0x60 6   PCI    Lvl Fixed0   1   0x0/0x17gem_gld_intr
2080xd0 14         Edg IPI    all 1   -         kcpc_hw_overflow_intr
2090xd1 14         Edg IPI    all 1   -         cbe_fire
2240xe0 15         Edg IPI    all 1   -         apic_error_intr
页: [1] 2 3 4 5 6 7 8 9
查看完整版本: 关于LINUX在中断(硬软)中不能睡眠的真正原因