内核线程、软中断和定时器有何区别
2016-06-19 13:44
281 查看
| ||
在慢速中断的过程中,允许别的中断发生 | ||
| ||
2.4中还有慢速中断吗? | ||
| ||
有,其实就是软中断. | ||
| ||
你好快,就成newbie了,我努力了好几个月才成newbie 慢速中断不应该是软中断吧?如果说慢速中断是可以中断的中断,那应该是那种没有XX_INTERRUPT标志的中断,系统响应时会打开中断。 软中断应该就是tasklet | ||
| ||
我觉得首先讲一下LINUX的内核机制: 传统的UNIX把内核分成两部分:TOP HALF和BOTTOMHALF.BOTTOM呢是由异步事件来调用的,其实在LINUX中不严格的说就是中断.TOP是由系统调用来调用的.注意这里的 BOTTOM HALF和LINUX2.2中的并在LINUX2.4也支持的BH机制不是一回事情. 好了,现在讲你问的问题: 软中断其实就是把一个异步事件的响应分成两个部分的一个部分.另一个叫硬中断.硬中断必须实时响应,软中断可以等有时间再做,LINUX怎么调度软中断,有三个途径,从系统掉用,异常和中断中返回的时候有检查要不要执行软终端. 对于一个时钟,很显然时钟中断的服务程序也被分成两个部分,一个就是硬中断,一个就是软中断了.你说的定时器我估计就是指时钟中断的软中断. 对与内核线程,LINUX从2.4的一些高端版本好象也开始采用了对某些软中断使用这中方法,即把软中断作为一个线程来执行. | ||
| ||
从他的意思来看就是软中断. 我原来比NEWBIE的级别还高一点呢,现在我换名字了. 你说的TASKLET只是软中断的一种类型. 对于中断的服务程序的设计,要具体对待,对于服务程序不大,没有必要采用软中断机制.直接关中断就可以了.你说的对XXX_INTERUPT如果象你那么设计,就不是采用软中断的机制了,在早期的UNIX是这么实现的,即一个中断服务不分成两个部分,只是在服务程序中开哪些中断.譬如 XENIX2.3.4就是这么设计的.至于LINUX可以不可以也这么直接写服务程序,我不知道.不过通常都是软硬中断分开的. | ||
| ||
我想你没有理解他的意思。他说的慢速中断是指没有SA_INTERRUPT标志的中断。 以下是相关代码: int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status; int cpu = smp_processor_id(); irq_enter(cpu, irq); status = 1; /* Force the "do bottom halves" bit */ /*慢速中断则开中断*/ if (!(action->flags & SA_INTERRUPT)) __sti(); do { status |= action->flags; action->handler(irq, action->dev_id, regs); action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); __cli(); irq_exit(cpu, irq); return status; } | ||
| ||
我觉得这个好象包括在软中断的机制里面吧? | ||
| ||
你这里采用的就是软中断的机制之一的BH机制. | ||
| ||
有没搞错?handle_IRQ_event()是IRQ!是硬中断! | ||
| ||
wheelz说得对,我说的慢速中断就是慢速中断,不是软中断 软中断的处理函数是do_softirq(),在kernel/softirq.c文件中 | ||
| ||
>你这里采用的就是软中断的机制之一的BH机制. 这是硬中断,不是BH机制: action->handler(irq, action->dev_id, regs); BH机制的函数是无参数无返回的:) | ||
| ||
你只知道其一,不知道其二,作为优化,软中断未必就必须那么执行,在没有其他硬中断的时候,就直接执行算了,你以为DO_IRQ里面的检查是做什么的呀?首先把ACTION=NULL的那一段的代码, | ||
| ||
在执行硬中断的时候,如果没有检测到其他的高级中断,直接执行他的软中断算了.因此,从概念上说,他是属于软中断的,尽管他同硬中断一道执行的. | ||
| ||
没有搞错,你假设一在他里面发生了高级的中断,他怎么处理?假设这个中断发生在其他的低级中断中,他怎么处理?还能执行到这个 IRQ_HANLDLER_EVENT么?不能,只能作为软中断执行了.这里做为优化,在没有检测到其他高级的中断的时候,直接就在硬中断后面把软中断执行掉了算了,从实际来讲,他是在硬中断之后执行的,但从概念上,他是属于软中断的范畴. | ||
| ||
你仔细看一ULK2的4.6和4.7节,看看hande_IRQ_event 是不是书上所讲的deferrable function的涵义. | ||
| ||
我都懒得跟你争,你居然认为handle_IRQ_event()是软中断? | ||
| ||
书上所讲的deferrable function指的是bottom half和tasklet,它们是由do_softirq调用的,而不是hande_IRQ_event. | ||
| ||
好,既然有处理软中断的例程,那么我问:软中断在哪里产生的?也就是说,在什么地方,硬中断把软中断挂入队列?你只能在DO_IRQ中找. 从整个中断发生的流程来看,先是从IRQXXX_INTERUPT跳到COMMON_INTERUPPT,直到调用DO_IRQ,根据软中断的定义我们可以知道,他必须由硬中断产生,并挂入软中断处理队列,请问,这个处理动作在哪里产生的? | ||
| ||
硬中断只产生中断请求队列,我确实不知道,硬中断还要处理中断请求.按照你的理解,第一个中断产生了一个handle_IRQ_event1中产生了一个中断2,它应该包含一个handle_IRQ_event2,只要没有被别的中断打断的话,就该执行完,那不就是event2在event1中执行了么? 你没有办法确定event2和event1是不是一个中断,假设是一个中断呢?你就必须考虑你的中断程序的可重入的问题.这无疑增加了驱动程序开发的难度. 另外,你说我错了没有什么关系,我错了,但是我可以说说我为什么有这么错误理解的理由,"懒得同我辩",搞得我好象是故意捣乱似的. | ||
| ||
我想问题已经很清楚了,这只是一个概念上的问题,并没有谁对谁错,在争下去也没有什么意义,我觉得我或者freshground或者wheelz是不会被你说服的,你觉得你会被我们说服吗?:) 这里我们称呼你所说的软中断为慢速中断是因为 1.ldd2上是这么写的,我们也就这么称呼了 2.如果我们称慢速中断为软中断,那就会把开中断执行的硬中断(当然,你称它为软中断)和softirq搞混 希望大家不要为了一个概念的问题伤了和气,这好像太不值得了 | ||
| ||
呵呵,“懒得和你争”其实是我调侃的气话,我愿意向你道歉:-)。 下面我就你在两个讨论话题中的问题和你探讨。我觉得你对中断部分的理解是错误的, 具体说就是你没有仔细看do_IRQ() >>硬中断只产生中断请求队列,我确实不知道,硬中断还要处理中断请求. 按照你的理解,第一个中断产生了一个handle_IRQ_event1中产生了一个中断2, 它应该包含一个handle_IRQ_event2,只要没有被别的中断打断的话,就该执行完, 那不就是event2在event1中执行了么? 你没有办法确定event2和event1是不是一个中断, 假设是一个中断呢?你就必须考虑你的中断程序的可重入的问题. 这无疑增加了驱动程序开发的难度. 没错,在这种情况下,event2是在event1中执行! 并且,event2和event1不可能是同一个中断, do_IRQ()保证了这一点,因为,如果同一个中断第二次发生,其相应desc->status有 IRQ_INPROGRESS标志,这样局部变量action==NULL,不会得到赋值, 因此goto out;同时,desc->status会并上IRQ_PENDING标志,这样, 当上一次中断响应完成后(for循环中,handle_IRQ_event之后), 会检查IRQ_PENDING标志,因而再循环一次 再次处理本中断, 这样也解决了重入的问题。 >>我觉得从开中断哪里讨论是不合适的,而是从DO_IRQ这个涵数开始, 在该书的P215页的注释607-617行,这一段代码,一定要执行到么? 如果回答是否定的,即有可能执行到也有可能不执行到,而是延时执行, 那么延时到哪里执行?一个就是FOR循环,一个就DO_SOFTIRQ了, 用ULK2的话说就是DEFFERABLE FUNCTION了,从这个意义上讲, 不就是软中断了么? 这段代码是一定要执行的,只有在action==NULL的情况下才会goto out; 那么什么情况下action会等于NULL呢?只有IRQ_DISABLED和IRQ_INPROGRESS, 也就是说只有当前中断被禁止或正在处理的情况下该循环 才不会执行。 下面是do_IRQ()的代码,取自2.4.20 /* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). */ asmlinkage unsigned int do_IRQ(struct pt_regs regs) { /* * We ack quickly, we don't want the irq controller * thinking we're snobs just because some other CPU has * disabled global interrupts (we have already done the * INT_ACK cycles, it's too late to try to pretend to the * controller that we aren't taking the interrupt). * * 0 return value means that this irq is already being * handled by some other CPU. (or is disabled) */ int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code */ int cpu = smp_processor_id(); irq_desc_t *desc = irq_desc + irq; struct irqaction * action; unsigned int status; #ifdef CONFIG_DEBUG_STACKOVERFLOW long esp; /* Debugging check for stack overflow: is there less than 1KB free? */ __asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (8191)); if (unlikely(esp < (sizeof(struct task_struct) + 1024))) { extern void show_stack(unsigned long *); printk("do_IRQ: stack overflow: %ld\n", esp - sizeof(struct task_struct)); __asm__ __volatile__("movl %%esp,%0" : "=r" (esp)); show_stack((void *)esp); } #endif kstat.irqs[cpu][irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); /* REPLAY is when Linux resends an IRQ that was dropped earlier WAITING is used by probe to mark irqs that are being tested */ status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); status |= IRQ_PENDING; /* we _want_ to handle it */ /* * If the IRQ is disabled for whatever reason, we cannot * use the action we have. */ action = NULL; if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { action = desc->action; status &= ~IRQ_PENDING; /* we commit to handling */ status |= IRQ_INPROGRESS; /* we are handling it */ } desc->status = status; /* * If there is no IRQ handler or it was disabled, exit early. Since we set PENDING, if another processor is handling a different instance of this same irq, the other processor will take care of it. */ if (!action) goto out; /* * Edge triggered interrupts need to remember * pending events. * This applies to any hw interrupts that allow a second * instance of the same irq to arrive while we are in do_IRQ * or in the handler. But the code here _disibledevent="darktable" valign="top" width="2%" rowspan="2"> |
| |
"呵呵,“懒得和你争”其实是我调侃的气话,我愿意向你道歉:-)。" 嘻嘻,那么认真干嘛?我从来就喜欢胡思乱想,胡言乱语,只要你不生气就好了.这么郑重的 道歉显得我太小气了哦. | ||
| ||
我觉得还是你们的有道理,在我仔细对照了ULK2和LDD2等资料之后,只是碰巧我找到了别人的学习笔记,理解的同我差不多,哈哈,也犯了和我一样的错误,转贴如下(太长了,只搞连接): http://joyfire.net/jln/kernel/2.html#I367 |