天天看點

關于LINUX在中斷(硬軟)中不能睡眠的真正原因

自陷就是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.

  1. 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).

  1. 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被中斷了,如果

QQ買号平台

中斷睡了,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做,響應應該是慢一些。因為排程的原因 。

繼續閱讀