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

2020-05-21 00:00:00 执行 系统 调度 进程 中断


自陷就是TRAP,LINUX的EXCEPTION-异常,有进程上下文。

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的处理才是非常不同。

我理解的前面的说的中断和进程无关大概就是这个意思(?)

我觉得,LINUX设计不让中断中睡眠是经过充分考虑的。seelp on interrupt(SOI)不允许是内核设计的原因,而不是有什么本质的无法更改的原因。

我同意zx_wing的说法,没有和进程关联的CONTEXT,而调度的基本单位是进程,因此KERNEL设计者无法容忍sleep on interrrupt(SOI).

下面的相同的讨论说的也很清楚:

think this should clear all confusions, apologies if this is too big
or irrelevant and doesnt make much sense, which I think is not the
case.

Note : The following explaination assumes that the isr and the
interrupted proceess share the stack, afaik isr can seperate stacks,
which is configurable, but I dont know how this explaination holds
good when the isr is having a seperate stack.

1. Why you are not allowed to sleep in an interrupt handler?Was this a
design decision or is there a fundamental reason that makes sleeping
interrupt handlers simply impossible? What about the page fault
handler - it (probably) sleeps when it has to swap in a page, why is
it possible to sleep for the page fault handler and not for an
interrupt handler?

-> Sleeping is implemented using scheduler. Scheduler only schedules
tasks (design decision to keep it simple). So you need a task context
to sleep in. Interrupt is not tied to a process (and uses stack of
whichever happens to be scheduled ) so it can't use the context
because it does not have to be in a sane state.

2. But why.....

You cannot sleep in an interrupt handler because interrupts do not have
a backing process context, and thus there is nothing to reschedule
back into. In other words, interrupt handlers are not associated with
a task, so there is nothing to "put to sleep" and (more importantly)
"nothing to wake up". They must run atomically.
The reason the page fault handler can sleep is that it is invoked only
by code that is running in process context. Because the kernel's own
memory is not pagable, only user-space memory accesses can result in a
page fault. Thus, only a few certain places (such as calls to
copy_{to,from}_user()) can cause a page fault within the kernel. Those
places must all be made by code that can sleep (i.e., process context,
no locks, etc).

3. However can't you consider the interrupt handler as running in the
context of the task A, that was incidentially running when the
interrupt occurred (the interrupt handler
uses the stack of task A, this is not always true, isr might have a
seperate stack). So wouldn't it conceptually be conceivable to put the
interrupt handler to sleep by saving the current CPU state (register
contents) with task A, putting task A asleep, and resume processing of
the interrupt once task A is rescheduled by the scheduler?
Of course this could be considered 'unfair' with respect to task A, in
that the interrupt has no relation to task A besides the fact that
they happend to be on the same CPU at the same time. But I am
interested in learning if there is any fundamental reason against
sleeping in an interrupt handler.

->There are bigger problems. The process is in an arbitrary state when
interrupt is invoked. So it might hold arbitrary spinlocks. It might
be on arbitrary wait_queues. Possibly other funny things might happen.
These either disallow sleeping or could interact badly with the
interrupt trying to sleep.

This is part of conversation happened on the same list before few
years, not verbatim though.
--

这里也说到了如果IRQ不用自己的STACK,而利用被中断任务(任务A)的STACK是否就可以SOI了的问题。
因为中断发生的CONTEXT和A无关,而是碰巧在同一个CPU上的一个任务A被中断了,如果中断睡了,A就回被殃及,系统就彻底乱了。
(和调度发生冲突了)。

至于schedule()会将任务在不同CPU之间分,而IRQ回来后如何?(假定IRQ不使用自己的STACK,可以回来的话)。
还有后一段说的其他各种复杂的问题。

总之,如果中断不THREAD化,应该无法SOI。所以LINUX(2。6)中shedule()中有检查不允许。

如果改动LINUX,如何改动小使得可以SOI?(虽然没有大意义,但作为讨论可以从讨论中学习其他的)。

中断和软中断的线程化和spin_lock的可sleep化这两个并不能提高系统的实时性。

比如spinlock, 就是为了短暂需要lock的时候让CPU空等待。这时比用可以sleep的锁要节省CPU而不是浪费。因为调度的耗费可能要比SPIN的耗费多的多。

linux的中断是半THREAD化的。你可以增加工作在THREAD(softirqd)中的比重,增加后,系统反映更慢了。比如你打一个字,一个网络包的处理,如果都用THREAD做,响应应该是慢一些。因为调度的原因 。

文章来源CU社区:关于LINUX在中断(硬软)中不能睡眠的真正原因

相关文章