免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: 思一克
打印 上一主题 下一主题

关于LINUX在中断(硬软)中不能睡眠的真正原因 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2007-06-27 14:27 |只看该作者
原帖由 zx_wing 于 2007-6-27 10:09 发表于 4楼  
呵呵,我最喜欢这种讨论了。先来献丑了,说说我的看法。
先把中断处理流程给出来

1.进入中断处理程序--->2.保存关键上下文---->3.开中断(sti指令)--->4.进入中断处理程序的handler--->5.关中 ...

我觉得主要是调度的问题,引入中断线程问题就基本解决了。

论坛徽章:
0
12 [报告]
发表于 2007-06-27 16:43 |只看该作者
LINUX上中断中不能睡眠(调用schedule,直接或间接)和“被中断的进程和中断本身无关系”无关。

前面有人说“被中断的进程和中断本身无关系”是不能睡眠的原因。我不理解,觉得说法不对。

论坛徽章:
0
13 [报告]
发表于 2007-06-27 17:15 |只看该作者
原帖由 思一克 于 2007-6-27 16:43 发表于 12楼  
LINUX上中断中不能睡眠(调用schedule,直接或间接)和“被中断的进程和中断本身无关系”无关。

前面有人说“被中断的进程和中断本身无关系”是不能睡眠的原因。我不理解,觉得说法不对。



这没什么不对,中断和自陷在执行的路径上,没有丝毫不同。如果说什么“中断是因为没有进程上下文,只有中断上下文”而不能睡眠的话;那么自陷同样“没有进程上下文,只有自陷上下文”。

但是自陷却可以睡眠,最明显的就是缺页异常,睡眠再正常不过了。就是因为当前发生的异常和当前进程有关系,把当前进程睡眠掉并不冤枉它。

论坛徽章:
0
14 [报告]
发表于 2007-06-27 17:52 |只看该作者
原帖由 Solaris12 于 2007-6-27 13:58 发表于 9楼  



呵呵,Solaris的低优先级中断是可以睡眠的,时钟中断也可以睡眠。尽管系统会尽量保证中断线程不去睡眠。例如,磁盘驱动的ISR里使用DRIVEDR mutex, 实际上系统把它当作自适应锁,当获取锁失败时,它先看其 ...

ISR(interrupt service routine)是不能睡眠的,我觉得你说的那个不是ISR,是IST(interrupt service thread).IST平时处于睡眠态,发生中断后,cpu执行ISR,在ISR中唤醒IST,中断服务的主体在IST中完成。引入IST后,一来可以减小内核体积,二来可以减小不可剥夺窗口,增强调度的实时性。WIN CE就是这样做的。不知Solaris的做法是否与此类似。请Solaris12兄指教

[ 本帖最后由 gta 于 2007-6-27 17:54 编辑 ]

论坛徽章:
0
15 [报告]
发表于 2007-06-27 19:35 |只看该作者
原帖由 gta 于 2007-6-27 17:52 发表于 14楼  
呵呵,Solaris的低优先级中断是可以睡眠的,时钟中断也可以睡眠。尽管系统会尽量保证中断线程不去睡眠。例如,磁盘驱动的ISR里使用DRIVEDR mutex, 实际上系统把它当作自适应锁,当获取锁失败时,它先看其 ...



退一万步说,假如中断可以睡眠,那么也决不是低优先级中断可以睡眠;而是当前进程为低优先级进程时能睡眠。不然那些进程调度算法不白写了?高优先级的进程有什么用?只要碰到个低优先级中断就被调度出去了。

虽然我不知道Solaris长的什么摸样。

论坛徽章:
0
16 [报告]
发表于 2007-06-27 20:24 |只看该作者
自陷就是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的处理才是非常不同。

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


原帖由 motalelf 于 2007-6-27 17:15 发表于 13楼  



这没什么不对,中断和自陷在执行的路径上,没有丝毫不同。如果说什么“中断是因为没有进程上下文,只有中断上下文”而不能睡眠的话;那么自陷同样“没有进程上下文,只有自陷上下文”。

但是自陷却可以 ...

论坛徽章:
0
17 [报告]
发表于 2007-06-27 20:25 |只看该作者
原帖由 gta 于 2007-6-27 17:52 发表于 14楼  
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()

论坛徽章:
0
18 [报告]
发表于 2007-06-27 20:30 |只看该作者
原帖由 motalelf 于 2007-6-27 19:35 发表于 15楼  
退一万步说,假如中断可以睡眠,那么也决不是低优先级中断可以睡眠;而是当前进程为低优先级进程时能睡眠。不然那些进程调度算法不白写了?高优先级的进程有什么用?只要碰到个低优先级中断就被调度出去了。

虽然我不知道Solaris长的什么摸样。



Solaris的中断服务线程有独立的调度优先级,一般是160-169。其中时钟中断最高,是169。


在Solaris里时钟中断是最高的调度优先级。

当然,高优先级中断一来,就立即执行,根本不涉及到调度问题。

我曾经给Solaris调度器提交过一个bug,其中就涉及到时钟中断睡眠的情形

[ 本帖最后由 Solaris12 于 2007-6-27 22:53 编辑 ]

论坛徽章:
0
19 [报告]
发表于 2007-06-27 22:00 |只看该作者

中断sleep, preempt和 实时性瓶颈介绍.

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

1.进入中断处理程序--->2.保存关键上下文---->3.开中断(sti指令)--->4.进入中断处理程序的handler--->5.关中 ...


里面很多说法不是很同意, 个人认为中断处理handler不能sleep原因应该不是上面那些.

我们都是从理论讲下面这些问题, 因为linux在很多地方做了保护, 所以直接sleep或者schedule()会导致内核异常.

首先分清楚, 我们讨论的是不能sleep, 而不是不能preempt.

1. 毫无疑问, 在关中断的时候不能sleep, 这点大家都知道, 因为时钟中断无法触发. 但不是所有情况下, 在关中断时sleep都会导致系统死掉, 在SMP的情况下, 可能系统不会死掉.

2.  中断的handler能否sleep?
     这其实和"中断没有自己的上下文"无关. CPU没有关中断, 中断有自己的上下文, 中断的上下文就是抢占的任务A的上下文.
     和栈溢出也没有关系, 现在的中断都是可以嵌套的, 如果中断sleep只会让后面的中断抢占其他任务, 根本不存在栈溢出问题, 不过现在内核的4K中断单独栈会有问题. 这会导致栈被破坏.

假设中断sleep了, 在调度的时候, 内核将中断的CS:eip和SS:esp保存在被抢占任务A的thread_info中, 当任务A被重新唤醒的时候, 任务A从中断的CS:eip开始执行, 这也能正常执行下去, 中断执行完后, 从ret_from_intr中返回. 可以恢复任务A的抢占前的场景.

Linux内核要实现成这样, 必须解决下面问题:
    中断sleep会增加普通任务的不确定性, 普通任务执行的时间, 实时性都得不到保障.
    和中断共享中断号的中断会受到影响, 现在的内核设置了INPROGRESS标志.
    中断因为借用了被抢占任务的上下文, 所以中断的处理受到任务上下文属性的限制.
    等等很多其他问题, 总之, 中断sleep会导致被抢占任务的不确定性, 并可能导致其他中断受影响.

总结:
    异步异常(中断)handler不是没有上下文, 而是没有固定的上下文,  如果使用被抢占的任务作为上下文, 一,自身的处理无法得到实时保障,导致系统不确定性, 二,任务受到影响.

如何解决:
    给中断handler提供固定的内核线程上下文!!
    这样, 中断不能sleep, 但中断的handler可以sleep!
    为每个中断号创建一个内核任务, 中断入口函数do_irq只是唤醒相应的中断任务, 中断任务去执行相应的handler.

好处:
     提高了系统的实时性. 后面可以详细讲.
坏处:
     降低了中断, 软中断的实时性, 所以不是所有的中断handler都可以在固定内核任务上下文中处理. 一般来说, 时钟中断必须保证其实时性, 所以留在中断上下文中.

  1. 介绍: Linux系统的实时性瓶颈在哪里??
  2.     一个实时性系统, 必须保证: 系统中优先级高的任务, 被唤醒后, 在很小的可控的延时内, CS:eip指令得到执行.
  3.     一个好的实时性系统, 必须保证: 系统中的所有等待运行的任务, 可以在一个固定的可接受的延时内, CS:eip指令得到执行.
  4.     这些延时包括 中断响应延时, 中断处理延时, 调度响应和调度处理延时.
复制代码


试想现有的系统, 一个任务可能在以下上下文中被唤醒:
1. 中断上下文, 如dma数据传输完成等等设备驱动.

        中断上下文唤醒任务后, 任务被加入到running队列, 返回, 继续执行中断, 中断执行完成后, 执行软中断, 中间可能会出现中断嵌套. 直到最后ret_from_intr, 才会判断是否需要抢占当前任务. 然后调用schedule(). 从队列被加入running队列到schedule()函数真正开始执行, 这段时间是中断处理延时+调度响应延时.

  如何缩短这部分延时和我们前面讨论的东西很有关.
    正是因为中断,软中断不能preempt, 不能sleep, 导致了系统的实时性变差. 而在这些时间中, 中断handler和软中断handler消耗绝大部分时间.
    设想一下, 如果中断handler和软中断handler放在专门的内核任务中执行, 中断handler中唤醒任务A, wakeup中通过优先级判断handler任务是否需要被任务A抢占, 如果需要, 设置handler任务的NEED_RESCHEDULE标志, 调用resched_task()可以马上进入schedule(), 其中的延时非常小, 而且非常稳定. 当然, 可能wakeup后, 立即有中断到来, 但因为中断执行路径变得非常短, 只是唤醒响应的handler任务, 可能只需要100行以内的代码.所以这些时间可以忽略不计. 这种做法可以极大提高系统的实时性.
   
2. 软中断上下文: 如定时器到期, 目的地是本地的报文送到socket层. 等等
        软中断的情况和中断类似, 可以通过将软中断线程化, 提高系统实时性.

3. 普通任务上下文, 如任务间通信等等.
   普通任务一旦在内核中执行了spin_lock(), 其他任务无法抢占这个CPU, 即使另外优先级高的任务不和它共享资源, 也无法及时得到调度. 当CPU变多, 内核代码变大的时候, 这个问题也变得非常突出, 所以spin_lock()也是一个影响系统实时性的设计. 如果将spin_lock变成可以抢占的锁, 会是怎样? 如果spin_lock可以抢占, 一旦任务B抢占了任务A, 而任务A执行了spin_lock(xxx), 恰好任务B也执行spin_lock(xxx), 必然导致内核死锁. 如果spin_lock()可以抢占, 且可以sleep(), 结果又会怎样. 任务B执行spin_lock(xxx)必然导致自己sleep, 这时任务A可以接着执行spin_unlock(xxx),唤醒任务B. 这时又有一个优先级反转问题需要解决, 假设任务B的优先级最高, 任务A最低, 任务C中等, B因为拿不到xxx锁而sleep, 重新调度, 结果调度到任务C执行, 任务B因此丧失了优先级优势, 这种情况在嵌入式系统中可能会导致很严重的问题. 所以任务A必须继承任务B的优先级, 重新调度的时候才能调度到任务A先运行.
   
--------------------------------------------------------------------------------------
上面这些系统问题的改正可以提高系统的实时性, 但整个内核的编程模型会变得更复杂. 这些东西就是Ingo Molnar在2005年实现的Realtime Patch中的核心思想, 但在2006年的Kernel Summit中, 引发了下面的讨论:

http://lwn.net/Articles/191782/

注意下面这段话.
The question was asked: why bother with sleeping locks? Making locks preemptible is seen by some as a way of papering over the real problem: long lock hold times. Why not simply fix those? The answer comes in a couple of parts:

    * Extensive efforts have been expended toward fixing lock problems for many years, and those efforts will continue into the future. The use of sleeping locks is not being used as an excuse to avoid fixing code which holds locks for too long.

    * Ensuring realtime response in the absence of preemptible locks requires auditing the entire body of kernel source - all eight million lines or so. That's a big job, and one which is hard to keep up with in an environment where nearly ten thousand lines of code are being changed every day. Sleeping locks reduce the audit requirements to a couple thousand lines - a much more tractable problem. For those who need realtime response, guaranteed, that is a good deal.

因为众多的争议, 中断和软中断的线程化和spin_lock的可sleep化没有合入主流内核中.

如果realtime patch合并到主流内核中, 可以满足: 系统中优先级高的任务, 被唤醒后, 在很小的可控的延时内, CS:eip指令得到执行.

但不能保证低优先级的时延, 这正是CFS要解决的问题, 设想一下, 要让系统中的任何优先级的任务在一定的时间内得到执行, 必然要求等待时间长的任务优先得到执行, CFS就是用等待时间来作为调度的依据, 而优先级居次. 有时间在讨论CFS的实现.

[ 本帖最后由 xiaozhaoz 于 2007-6-28 00:41 编辑 ]

论坛徽章:
0
20 [报告]
发表于 2007-06-27 22:04 |只看该作者
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP