• 中断线程


    参考: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资源,要是在中断线程中做大量的工作,那系统的吞吐量将会大大降低?

  • 相关阅读:
    Assets Pipeline
    how to execute-shell-commands by ruby
    DFS---迷宫问题
    病毒感染监测
    RE数组开多大?
    C++如何输入含空格的字符串
    后缀算术表达式
    中缀表达式转化为后缀表达式
    基于两端操作的循环队列的实现---怎么判断队满??
    循环队列--忘记分配空间和如何用tag判断队空队满
  • 原文地址:https://www.cnblogs.com/openix/p/3296142.html
Copyright © 2020-2023  润新知