中断下半部机制-softirq-Tasklet-工作队列

版权声明:关注微信公众号:嵌入式Linux QQ群:69759006 了解更多嵌入式方面知识 https://blog.csdn.net/weiqifa0/article/details/88168944

中断上半部和下半部

在中断上半部,就是中断处理函数里面,是关中断的,所以为了快速执行,不能放太多的处理代码,只能执行非常短,这就衍生出了中断下半部。下半部主要是为了方便执行大量和本次中断相关的代码。

中断下半部的三种机制

下半部 上下文 顺序执行保障
softirq 中断 随意,同类型都可以在不同处理器同时执行,代码执行效率非常高
tasklet 中断 用softirq机制实现,同类型不能同时执行
workqueue 进程 不保障,可能被调度和抢占

softirq

具体示例查看内核代码
kernel/kernel/time/timer.c
注册softirq

void open_softirq(int nr, void (*action)(struct softirq_action *)) 
{ 
    softirq_vec[nr].action = action; 
}

触发softirq

void raise_softirq(unsigned int nr) 
{ 
    unsigned long flags;

    local_irq_save(flags); 
    raise_softirq_irqoff(nr); 
    local_irq_restore(flags); 
}

disable/enable softirq

//disable
static inline void local_bh_disable(void) 
{ 
    __local_bh_disable_ip(_THIS_IP_, SOFTIRQ_DISABLE_OFFSET); 
}

static __always_inline void __local_bh_disable_ip(unsigned long ip, unsigned int cnt) 
{ 
    preempt_count_add(cnt); 
    barrier(); 
}
//enable
static inline void local_bh_enable(void) 
{ 
    __local_bh_enable_ip(_THIS_IP_, SOFTIRQ_DISABLE_OFFSET); 
}

void __local_bh_enable_ip(unsigned long ip, unsigned int cnt) 
{ 
    WARN_ON_ONCE(in_irq() || irqs_disabled());-----------(1) 

    preempt_count_sub(cnt - 1); ------------------(2)

    if (unlikely(!in_interrupt() && local_softirq_pending())) { -------(3) 
        do_softirq(); 
    }

    preempt_count_dec(); ---------------------(4) 
    preempt_check_resched(); 
}

Tasklet

定义一个Tasklet

#define DECLARE_TASKLET(name, func, data) \ 
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }

#define DECLARE_TASKLET_DISABLED(name, func, data) \ 
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }

调度一个Tasklet

static inline void tasklet_schedule(struct tasklet_struct *t) 
{ 
    if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) 
        __tasklet_schedule(t); 
}

工作队列workqueue

声明一个workqueue

    int irq2;           
    struct work_struct irq2_work;                                                                                                  
    struct workqueue_struct *irq2_work_queue;

初始化一个workqueue

    INIT_WORK(&acc->irq2_work, lis3dh_acc_irq2_work_func);                                                                         
    acc->irq2_work_queue = create_singlethread_workqueue("lis3dh_acc_wq2");
    if (!acc->irq2_work_queue) {
        err = -ENOMEM;
        dev_err(&client->dev, "cannot create work queue2: %d\n", err);
        goto err_destoyworkqueue1;
    }  

调度执行一个workqueue

queue_work(acc->irq2_work_queue, &acc->irq2_work);                                                                             
printk(KERN_INFO "%s: isr2 queued\n", LIS3DH_ACC_DEV_NAME);

销毁一个workqueue

destroy_workqueue(acc->irq2_work_queue); 

只是简单记录~面试的时候会问他们的差别,还有实现下半部的方式,主要性能方面softirq可以多cpu执行,性能会最快,workqueue被调度执行,性能会比较低下。后续有时间再继续更新。

猜你喜欢

转载自blog.csdn.net/weiqifa0/article/details/88168944