目录

1 引入

 2 内核机制

2.1 调用 request_threaded_irq 后内核的数据结构

2.2  request_threaded_irq

2.3 中断的执行过程


1 引入

复杂、耗时的事情,尽量使用内核线程来处理。工作队列用起来挺简单,但是它有一个缺点:工作队列中有多个 work,前一个 work 没处理完会影响后面的 work。解决方法有很多种,比如干脆自己创建一个内核线程,不跟别的 work 凑在一块了。在 Linux 系统中,对于存储设备比如 SD/TF 卡,它的驱动程序就是这样做的,它有自己的内核线程。 
对于中断处理,还有另一种方法:threaded  irq,线程化的中断处理。中断的处理仍然可以认为分为上半部、下半部。上半部用来处理紧急的事情,下半部用一个内核线程来处理,这个内核线程专用于这个中断。 
内核提供了这个函数: 

 你可以只提供 thread_fn,系统会为这个函数创建一个内核线程。发生中断时,系统会立刻调用 handler 函数,然后唤醒某个内核线程,内核线程再来执行thread_fn 函数。

 2 内核机制

2.1 调用 request_threaded_irq 后内核的数据结构

2.2  request_threaded_irq

request_threaded_irq 函数,肯定会创建一个内核线程。 源码在内核文件 kernel\irq\manage.c 中, 

int request_threaded_irq(unsigned int irq, irq_handler_t handler, 
       irq_handler_t thread_fn, unsigned long irqflags, 
       const char *devname, void *dev_id) 
{ 
    // 分配、设置一个 irqaction 结构体 
  action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); 
  if (!action) 
    return -ENOMEM; 
 
  action->handler = handler; 
  action->thread_fn = thread_fn; 
  action->flags = irqflags; 
  action->name = devname; 
  action->dev_id = dev_id; 
 
    retval = __setup_irq(irq, desc, action);  // 进一步处理 
} 

__setup_irq 函数代码如下(只摘取重要部分):

if (new->thread_fn && !nested) { 
    ret = setup_irq_thread(new, irq, false); 

 setup_irq_thread 函数代码如下(只摘取重要部分): 

  if (!secondary) { 
    t = kthread_create(irq_thread, new, "irq/%d-%s", irq, 
           new->name); 
  } else { 
    t = kthread_create(irq_thread, new, "irq/%d-s-%s", irq, 
           new->name); 
    param.sched_priority -= 1; 
  } 
new->thread = t; 

2.3 中断的执行过程

对于 GPIO 中断, 调用关系如下,反过来看:

Breakpoint 1, gpio_keys_gpio_isr (irq=200, dev_id=0x863e6930) at drivers/input/keybo
ard/gpio_keys.c:393 
393 { 
(gdb) bt 
#0  gpio_keys_gpio_isr (irq=200, dev_id=0x863e6930) at drivers/input/keyboard/gpio_k
eys.c:393 
#1  0x80270528 in __handle_irq_event_percpu (desc=0x8616e300, flags=0x86517edc) at ke
rnel/irq/handle.c:145 
#2  0x802705cc in handle_irq_event_percpu (desc=0x8616e300) at kernel/irq/handle.c:18
5 
#3  0x80270640 in handle_irq_event (desc=0x8616e300) at kernel/irq/handle.c:202 
#4  0x802738e8 in handle_level_irq (desc=0x8616e300) at kernel/irq/chip.c:518 
#5  0x8026f7f8 in generic_handle_irq_desc (desc=<optimized out>) at ./include/linux/i
rqdesc.h:150 
#6  generic_handle_irq (irq=<optimized out>) at kernel/irq/irqdesc.c:590 
#7  0x805005e0 in mxc_gpio_irq_handler (port=0xc8, irq_stat=2252237104) at drivers/gp
io/gpio-mxc.c:274 
#8  0x805006fc in mx3_gpio_irq_handler (desc=<optimized out>) at drivers/gpio/gpio-mx
c.c:291 
#9  0x8026f7f8 in generic_handle_irq_desc (desc=<optimized out>) at ./include/linux/i
rqdesc.h:150 
#10 generic_handle_irq (irq=<optimized out>) at kernel/irq/irqdesc.c:590 
#11 0x8026fd0c in __handle_domain_irq (domain=0x86006000, hwirq=32, lookup=true, regs
=0x86517fb0) at kernel/irq/irqdesc.c:627 
#12 0x80201484 in handle_domain_irq (regs=<optimized out>, hwirq=<optimized out>, dom
ain=<optimized out>) at ./include/linux/irqdesc.h:168 
#13 gic_handle_irq (regs=0xc8) at drivers/irqchip/irq-gic.c:364 
#14 0x8020b704 in __irq_usr () at arch/arm/kernel/entry-armv.S:464 

我 们 只 需 要 分 析 __handle_irq_event_percpu 函 数 , 它 在kernel\irq\handle.c 中:

线程的处理函数为 irq_thread,代码在 kernel\irq\handle.c 中: 

Logo

更多推荐