linux中断处理子系统小结
发表时间:2020-10-19
发布人:葵宇科技
浏览次数:51
前面的博文中, 大年夜致分散介绍了一些中断相干的器械, 然则对软中断的部分没有细心介绍, 在这里同一总结一下.
中断上半部的处理,汇编到request_irq的handle之间的过程.
http://blog.csdn.net/jackjones_008/article/details/42387241
MIPS平台的一点记录
http://blog.csdn.net/jackjones_008/article/details/41945909
tasklet/workqueue的介绍鄙人面这篇博文中有比较具体的介绍.
http://blog.csdn.net/jackjones_008/article/details/42295411
中断的处理, 起首当然是硬件中断产生后汇编部分的处理, 然后在hardirq处理完之后, 在函数irq_exit中, 如不雅发明当前没有hardirq并且softirq没有被禁止,
也没有pending的本地softirq, 则会显示的调用do_softirq 去处理softirq. 在处理softirq的过程中, 是会樊篱硬件中断的.
asmlinkage void do_softirq(void) { __u32 pending; unsigned long flags; if (in_interrupt()) return; local_irq_save(flags); pending = local_softirq_pending(); if (pending) __do_softirq(); local_irq_restore(flags); }
在__do_softirq 琅绫擎, 在获得pending的softirq后, 又会打开硬件中断. 然后会去依次处理pending 的softirq.
这个依次, 其实就是根据enum中的定义大年夜 HI_SOFTIRQ 履行到 RCU_SOFTIRQ.
再多烦琐一下, 为什么会有pending的softirq呢, 因为代码有些处所去调用了 __raise_softirq_irqoff .
我们还可以留意到, __do_softirq 琅绫擎定义了一个max_restart, 这个值是10, 是体系的一个折中, 处理软中断, 然则不克不及过度的影响其他过程的履行.
完成不了的, 可以交给 ksoftirqd 这个内核thread去做.
asmlinkage void __do_softirq(void) { struct softirq_action *h; __u32 pending; int max_restart = MAX_SOFTIRQ_RESTART; int cpu; pending = local_softirq_pending(); account_system_vtime(current); __local_bh_disable((unsigned long)__builtin_return_address(0)); trace_softirq_enter(); cpu = smp_processor_id(); restart: /* Reset the pending bitmask before enabling irqs */ set_softirq_pending(0); local_irq_enable(); h = softirq_vec; do { if (pending & 1) { int prev_count = preempt_count(); h->action(h); if (unlikely(prev_count != preempt_count())) { printk(KERN_ERR "huh, entered softirq %td %p" "with preempt_count %08x," " exited with %08x?\n", h - softirq_vec, h->action, prev_count, preempt_count()); preempt_count() = prev_count; } rcu_bh_qsctr_inc(cpu); } h++; pending >>= 1; } while (pending); local_irq_disable(); pending = local_softirq_pending(); if (pending && --max_restart) goto restart; if (pending) wakeup_softirqd(); trace_softirq_exit(); account_system_vtime(current); _local_bh_enable(); }
enum { HI_SOFTIRQ=0, TIMER_SOFTIRQ, NET_TX_SOFTIRQ, NET_RX_SOFTIRQ, BLOCK_SOFTIRQ, TASKLET_SOFTIRQ, SCHED_SOFTIRQ, HRTIMER_SOFTIRQ, RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ NR_SOFTIRQS };
接上, restart 中处理完后, 还有pending的softirq的话, 就交给内核过程 ksoftirqd 去做. 这个内核过程也挥菰式的调用 do_softirq 去处理.
static int ksoftirqd(void * __bind_cpu) { set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { preempt_disable(); if (!local_softirq_pending()) { preempt_enable_no_resched(); schedule(); preempt_disable(); } __set_current_state(TASK_RUNNING); while (local_softirq_pending()) { /* Preempt disable stops cpu going offline. If already offline, we'll be on wrong CPU: don't process */ if (cpu_is_offline((long)__bind_cpu)) goto wait_to_die; do_softirq(); preempt_enable_no_resched(); cond_resched(); preempt_disable(); rcu_qsctr_inc((long)__bind_cpu); } preempt_enable(); set_current_state(TASK_INTERRUPTIBLE); } __set_current_state(TASK_RUNNING); return 0; wait_to_die: preempt_enable(); /* Wait for kthread_stop */ set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { schedule(); set_current_state(TASK_INTERRUPTIBLE); } __set_current_state(TASK_RUNNING); return 0; }
这时, 又弗成避免的回到了中断上半部和下半部的话题, 上半部我们可以懂得为一向履行到 request_irq 中注册的那个 handle 为止. 而softirq 开端的处理都是属于下半部的处理.
鄙人半部的处理中, 根据睡眠与否可以应用tasklet和workqueue的机制.
其实tasklet也是属于softirq的一种, 并且弗成睡眠. workqueue的机制则是交给了内核thread去履行, 可以许可睡眠.