中断线程

参考:2.6.34

 

看了下2.6.34中的中断线程,但是在《内核设计与实现》3ed_CN的p_90~p_130内并未提起中断线程,因此做下记录,其中关于kthread_create函数已在“工作队列”笔记中做了说明。

通常通过request_irq申请中断资源时并未注册中断线程处理函数,可以通过request_threaded_irq来注册中断线程处理函数。

注册中断线程处理函数:

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) 

    |---->struct irqaction *action;

    |     struct irq_desc *desc;

    |     des = irq_to_desc(irq); 

    |     action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);

    |

    |----action->handler = handler;中断处理函数

    |    action->thread_fn = thread_fn; 中断线程处理函数

    |    action->name = devname;

    |    action->dev_id = dev_id;

    |

    |---->int retval = __setup_irq(irq, desc, action);


__setup_irq()中新建中断线程
static int __setup_irq(unsigned int irq,

                       struct irq_desc *desc, 

                       struct irqaction *new)

    |---->int nested = desc->status & IRQ_NESTED_THREAD;

    |

    |此处考虑创建中断线程;

    |关于IRQ_NESTED_THREAD的意义,我并没有理解,存疑

    |if (new->thread_fn && !nested) {

    |

    |----struct task_struct *t;

    |    t = kthread_create(irq_thread, new, "irq/%d-%s", irq, new->name);

    |    get_task_struct(t);

    |    new->thread = t;

    |}

    |

    |----int shared = 0;

    |    struct irqaction **old_ptr;

    |    通过遍历irq_desc中域irqaction*,获得可添加irqaction的位置;

    |    若为首次添加,则shared = 0;否则shared = 1;

    |    是否首次添加的区被至于在于对irq_desc实例的status域的影响,

    |    因为第一个irqaction将决定是否兼容后续的irqaction添加。

    |    在__setup_irq中有一系列的兼容性检查,此分析中省略了。

    |----若首次添加,则执行......

    |----new->irq = irq;

    |----*old_ptr = new;

    |

    |----if(new->thread) wake_up_process(new->thread); 见本记录最后对此的疑问


若首次在irq_desc中域irqaction*添加irqaction,则执行如下流程:
|---->irq_chip_set_defaults(desc->chip);

|---->init_waitqueue_head(&desc->wait_for_threads);

|---->if(new->flags & IRQF_TRIGGER_MASK)设置中断被触发的类型。

|---->desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_OENSHOT |

|                      IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);

|---->new->flags & IRQF_ONESHOT ? desc->status |= IRQ_ONESHOT :(void)0;

|---->if(!desc->status & IRQ_NOAUTOEN){

|    desc->depth = 0;

|    desc->status &= ~IRQ_DISABLED;

|    desc->chip->startup(irq);

|     }else desc->depth = 1;

 

何时唤醒中断线程?

handle_IRQ_event中,若中断处理函数返回值为IRQ_WEAK_THREAD,则wake_up_process(action->thread)

中断处理线程的执行:

static int irq_thread(void *data)

{                                                                                                                   

        struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2, };

        struct irqaction *action = data; 

        struct irq_desc *desc = irq_to_desc(action->irq);

        int wake, oneshot = desc->status & IRQ_ONESHOT;



        sched_setscheduler(current, SCHED_FIFO, &param);

        current->irqaction = action; 



        while (!irq_wait_for_interrupt(action)) {

+-- 18 lines: irq_thread_check_affinity(desc, action);--------------------------------------------------------------

                {       

                        raw_spin_unlock_irq(&desc->lock);



                        action->thread_fn(action->irq, action->dev_id);

+--  3 lines: if (oneshot)------------------------------------------------------------------------------------------

                }       

+--  3 lines: wake = atomic_dec_and_test(&desc->threads_active);----------------------------------------------------

                if (wake && waitqueue_active(&desc->wait_for_threads))

                        wake_up(&desc->wait_for_threads);

        }       

+--  5 lines: Clear irqaction. Otherwise exit_irq_thread() would make-----------------------------------------------

        current->irqaction = NULL; 

        return 0;

}

 

疑问:1、固然在__setup_irq的最后唤醒中断线程没有错误,但是为什么要在__setup_irq的最后唤醒中断线程,如果不唤醒会导致错误么?

          2、内核中既有中断线程,又有工作线程,为何同时应入这两种方法?两者的区别和各自的优势又是什么?

          3、当然,我们也注意到中断线程的调度策略总被设置为“SCHED_FIFO",而工作线程默认的调度策略是”SCHED_NORMAL", 为什么要把一个内核线程的调度策略设置成“SCHED_FIFO", SCHED_FIFO将一直持有cpu资源,要是在中断线程中做大量的工作,那系统的吞吐量将会大大降低?

 

你可能感兴趣的:(线程)