中断为何会丢失

正在读ULK3,第四章中断中关于__DO_IRQ()的代码中涉及中断丢失的部分有点迷惑。代码如下:
  1. spin_lock(&(irq_desc[irq].lock));
  2. irq_desc[irq].handler->ack(irq);
  3. irq_desc[irq].status &= ~(IRQ_REPLAY | IRQ_WAITING);
  4. irq_desc[irq].status |= IRQ_PENDING;
  5. if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))
  6.     && irq_desc[irq].action) {
  7.      irq_desc[irq].status |= IRQ_INPROGRESS;
  8.      do {
  9.           irq_desc[irq].status &= ~IRQ_PENDING;
  10.           spin_unlock(&(irq_desc[irq].lock));
  11.           handle_IRQ_event(irq, regs, irq_desc[irq].action);
  12.           spin_lock(&(irq_desc[irq].lock));
  13.      } while (irq_desc[irq].status & IRQ_PENDING);
  14.      irq_desc[irq].status &= ~IRQ_INPROGRESS;
  15. }
  16. irq_desc[irq].handler->end(irq);
  17. spin_unlock(&(irq_desc[irq].lock));
复制代码

按照我对ULK3的理解,假设有两个CPU分别称为A和B。B正在执行中断服务程序handle_IRQ_event(),此时同类型的中断在A上发生,那么A将进入__DO_IRQ()执行上面的代码片段。如果在A确认中断之前,B执行了disable_irq()屏蔽了IRQ线并置IRQ_DISABLED标志,那么A执行到第5行时由于IRQ_DISABLED标志置位,A直接从__DO_IRQ()返回,这就是中断的丢失。我有两个地方不明白:

1. 这里ULK3为什么要强调在A确认中断之前?难道确认中断之后就不会丢失中断吗?
2. 这种情况下,中断真的会丢失吗?A在进入do_IRQ()函数之后,在第三行将IRQ_PENDING置位了,所以虽然A从do_IRQ()返回,但B在执行完handle_IRQ_event()后循环条件成立(IRQ_PENDING置位),所以仍然会再次调用handle_IRQ_event来处理,所以我觉得这里中断不会丢失呀。

当中断处理期间同一个CPU上同类型的中断不会再次发生。但是其他CPU上的同类型中断却会再次发生,这也是中断丢失的必要条件。我不理解的是中断如何丢失,代码中的那个循环应该可以保证不会丢失中断的。

 

> 1. 这里ULK3为什么要强调在A确认中断之前?难道确认中断之后就不会丢失中断吗?

A确认中断时,已经获得了irq_desc[irq].lock,而disable_irq必须也要获取到该锁,所以,当A确认中断之后,B已经没有机会disable_irq了,必须要等到A执行完之后,才可以;


> 2. 这种情况下,中断真的会丢失吗?A在进入do_IRQ()函数之后,在第三行将IRQ_PENDING置位了,所以虽然A从do_IRQ()返回,但B在执行完handle_IRQ_event()后循环条件成立(IRQ_PENDING置位),所以仍然会再次调用handle_IRQ_event来处理,所以我觉得这里中断不会丢失呀。

英文版上说的是“A hardware device raises the IRQ line, and the multi-APIC system selects our CPU for handling the interrupt. Before the CPU acknowledges the interrupt, the IRQ line is masked out by another CPU;”,这里很微妙,是的你说的很对,do_IRQ()本身可以确保中断不丢失,但是为什么disable_irq不能被内核的其他函数调用呢?如果那里只是单纯的成对使用disable_irq和enable_irq,那就会有中断丢失了,不是吗?呵呵,这里说的不清楚,只是说明了by another CPU, 而没有说by another CPU who's  not executing __do_IRQ().

 

> 首先,外部中断源能否在上一次中断未被处理的情况下,再一次发出中断信号,是个问题;

这可能与中断控制器有关,我记得8259A可以通过编程使它在前一个中断没有确认的情况下不会接受同类型的下一个中断。此时,对应的IRQ线和设备都无法继续。我也一直有个问题:PIC是如何阻塞一个设备的,PIC是否也需要对设备做确认?

> 其次,即使可以,那是否可以多次中断,一次处理呢?只记录了pending的状态,而没有记录pending的> 次数,所以只会而且一定会调用一次ISR。一般的情况都好理解,假设网卡收到一个包,发出中断,并把包> 存放在某处,继续接受下一个包,接收到之后,有发出中断。。。这样,调用ISR的时候,只需要去存包的> 地方取包就可以了,pending的包都可以取到。
> 我疑惑的是时钟中断丢失的情形,但是查资料发现,6.4.1 找回遗失的时钟中断>http://book.51cto.com/art/200810/93782.htm,说明,对于需要特殊处理的中断,内核是考虑到并> 做了处理的。

是的,网卡的例子应该适用许多设备对数据处理的情况,因为数据都是被缓冲的。而时间流逝过去就无法找回来,所以内核对它特别关照了。不论何种设备,办法似乎不是在从内核中断机制本身防止中断丢失,而是依靠具体的中断服务例程的补充。例如,时钟中断与TSC比照来做修正。网卡一个收多个包也可以认为是一种修正。

你可能感兴趣的:(linux设备驱动)