关于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)的PR

自陷就是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做,响应应该是慢一些。因为调度的原因 。

目录
相关文章
|
4月前
|
安全 小程序 Linux
Linux中信号是什么?Ctrl + c后到底为什么会中断程序?
信号在进程的学习中是一个非常好用的存在,它是软件层次上对中断机制的一种模拟,是异步通信方式,同时也可以用来检测用户空间到底发生了什么情况,然后系统知道后就可以做出相应的对策。
115 6
|
6月前
|
存储 负载均衡 网络协议
X86 linux异常处理与Ipipe接管中断/异常
本文讲述了X86平台上Xenomai的ipipe如何接管中断处理。首先回顾了X86中断处理机制,包括IDT(中断描述符表)的工作原理和中断处理流程。接着详细介绍了Linux中中断门的初始化,包括门描述符的结构、中断门的定义和填充,以及IDT的加载。在异常处理部分,文章讲解了早期异常处理和start_kernel阶段的异常向量初始化。最后,讨论了APIC和SMP中断在IDT中的填充,以及剩余中断的统一处理。文章指出,ipipe通过在中断入口处插入`__ipipe_handle_irq()`函数,实现了对中断的拦截和优先处理,确保了实时性。
139 0
X86 linux异常处理与Ipipe接管中断/异常
|
存储 Linux
Linux内核18-中断和异常的嵌套处理
Linux内核18-中断和异常的嵌套处理
Linux内核18-中断和异常的嵌套处理
|
6月前
|
人工智能 Ubuntu Linux
linux配置魔搭社区modelscope时的whl下载中断问题和解决方案
本文提供了断点续传和手动安装两个方案。
254 3
|
6月前
|
存储 安全 Linux
Linux中断(tasklet,工作队列,内核线程的使用)
Linux中断(tasklet,工作队列,内核线程的使用)
127 0
|
6月前
|
存储 Linux API
Linux系统对中断的处理
Linux系统对中断的处理
87 0
|
存储 网络协议 Linux
基于ARM+Linux中断系统详细分析
基于ARM+Linux中断系统详细分析
基于ARM+Linux中断系统详细分析
|
6月前
|
Linux 虚拟化 芯片
Linux 中断子系统中GIC 中断控制器基本分析
Linux 中断子系统中GIC 中断控制器基本分析
196 0
|
Linux
Linux内核分析与应用5-中断
Linux内核分析与应用5-中断
65 0
|
Linux 调度
Linux驱动中断下半部的三种方法
Linux驱动中断下半部的三种方法