中断详解(七)——软中断与微任务
来源:互联网 发布:php 伪静态 编辑:程序博客网 时间:2024/04/28 14:33
我们知道,中断处理程序被分为上半部函数和下半部函数。而软中断、微任务、工作队列都是是下半部函数的机制。(至于工作队列的方式,她是以另一个线程的方式实现的,初始化时创建,调用时唤醒,其实request_thread_irq是将中断线程化,包括利用定时器实现延时处理,这都不是在中断上下文中)
软中断和微任务都是通过do_softirq执行的。
中断处理在do_IRQ中调用软中断 do_softirq
中断处理在do_IRQ中调用软中断 do_softirq
unsigned int __irq_entry do_IRQ(struct pt_regs *regs){ ...... irq_exit();} void irq_exit(void) { ...... invoke_softirq(); //调用软irq处理} #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED# define invoke_softirq() __do_softirq()#else# define invoke_softirq() do_softirq()#endif
软中断:
获取软中断向量表
asmlinkage void do_softirq(void){ __u32 pending; unsigned long flags; // 这个函数判断,如果当前有硬件中断嵌套,或有软中断正在执行时候,则马上返回 //入口判断主要是为了和 ksoftirqd 互斥。 if (in_interrupt()) return; local_irq_save(flags);// 关中断执行以下代码 pending = local_softirq_pending();// 判断是否有 pending 的软中断需要处理。 if (pending) // 如果有则调用 __do_softirq() 进行实际处理 __do_softirq(); local_irq_restore(flags); // 开中断继续执行 }
asmlinkage void __do_softirq(void){ struct softirq_action *h; // 软件中断处理结构,此结构中包括了 ISR 中 注册的回调函数。 __u32 pending; unsigned long end = jiffies + MAX_SOFTIRQ_TIME; int cpu; int max_restart = MAX_SOFTIRQ_RESTART; pending = local_softirq_pending(); // 得到当前所有 pending 的软中断。 account_system_vtime(current); /* 执行到这里要屏蔽其他软中断,每个 CPU 上同时运行的软中断只能有一个。*/ __local_bh_disable((unsigned long)__builtin_return_address(0), SOFTIRQ_OFFSET); lockdep_softirq_enter(); cpu = smp_processor_id(); // 针对 SMP 得到当前正在处理的 CPU restart: // 每次循环在允许硬件 ISR 强占前,首先重置软中断的标志位。 /* Reset the pending bitmask before enabling irqs */ set_softirq_pending(0); // 开中断运行,(注意:以前运行状态一直是关中断运行) //这里以后的代码才可能被硬件中断抢占。 local_irq_enable(); h = softirq_vec; //获取软中断向量表 do { if (pending & 1) { // 如果对应的软中断设置 pending 标志则表明需要进一步处理他所注册的函数。 int prev_count = preempt_count(); kstat_incr_softirqs_this_cpu(h - softirq_vec); trace_softirq_entry(h, softirq_vec); h->action(h); // 在这里执行了这个软中断所注册的回调函数。 trace_softirq_exit(h, softirq_vec); if (unlikely(prev_count != preempt_count())) { printk(KERN_ERR "huh, entered softirq %td %s %p" "with preempt_count %08x," " exited with %08x?\n", h - softirq_vec, softirq_to_name[h - softirq_vec], h->action, prev_count, preempt_count()); preempt_count() = prev_count; } rcu_bh_qs(cpu); } h++;// 继续找,直到把软中断向量表中所有 pending 的软中断处理完成。 pending >>= 1; // 从代码里能看出按位右移操作,表明一次循环只处理 32 个软中断的回调函数 } while (pending); local_irq_disable(); // 再次关中断 pending = local_softirq_pending(); if (pending) { if (time_before(jiffies, end) && !need_resched() && --max_restart) // 如果刚才触发的硬件中断注册了软中断,并且重复执行次数没有到 max_restart个 次的话 goto restart; //超过max_restart个硬件中断注册了软中断,满负荷,需要另开线程处理软中断 // 此函数实际是调用 wake_up_process() 来唤醒 ksoftirqd wakeup_softirqd(); } lockdep_softirq_exit(); account_system_vtime(current); // 到最后才开软中断执行环境,允许软中断执行。注意:这里 // 使用的不是 local_bh_enable(),不会再次触发 do_softirq()的调用。 __local_bh_enable(SOFTIRQ_OFFSET); }
void wakeup_softirqd(void){ /* Interrupts are disabled: no need to stop preemption */ struct task_struct *tsk = __get_cpu_var(ksoftirqd); //ksoftirqd 线程 if (tsk && tsk->state != TASK_RUNNING) wake_up_process(tsk); //唤醒ksoftirqd线程 } static int ksoftirqd(void * __bind_cpu){ // 设置当前进程状态为可中断的状态, set_current_state(TASK_INTERRUPTIBLE); current->flags |= PF_KSOFTIRQD; // 设置当前进程不允许被挂起 while (!kthread_should_stop()) { //循环判断当前进程是否会停止 preempt_disable();// 禁止当前进程被抢占。 if (!local_softirq_pending()) { // 首先判断系统当前没有需要处理的 pending 状态的软中断 // 没有的话在主动放弃 CPU 前先要允许抢占,因为一直是在不允许抢占状态下执行的代码。 preempt_enable_no_resched(); // 主动放弃 CPU 将当前进程放入睡眠队列,并转换新的进程执行(调度器相关不记录在此),但此进程再次被唤醒时,直接执行下一语句。 schedule(); preempt_disable(); // 当进程再度被调度时,在以下处理期间内禁止当前进程被抢占。 } __set_current_state(TASK_RUNNING); // 设置当前进程为运行状态。 /* * 循环判断是否有 pending 的软中断,如果有则调用 do_softirq()来做具体处理。 * 注意:这里又是个 do_softirq() 的入口点, * 那么在 __do_softirq() 当中循环处理 10 次软中断的回调函数后, * 如果更有 pending 的话,会又调用到这里 * 那么在这里则又会有可能去调用 __do_softirq() 来处理软中断回调函数。 * 在__do_softirq()中,处理 10 次还处理不完的话说明系统正处于繁忙状态。 * 综上,在系统非常繁忙时,这个进程将会和 do_softirq() 相互交替执行, * 这时此进程占用 CPU 应该会非常高, */ 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))// 如果当前被关联的 CPU 无法继续处理则跳转 goto wait_to_die; // 到 wait_to_die 标记出,等待结束并退出。 // 执行 do_softirq() 来处理具体的软中断回调函数。 //如果此时有一个正在处理的软中断的话,则会马上返回 注意in_interrupt() do_softirq(); preempt_enable_no_resched();// 允许当前进程被抢占。 // 这个函数有可能间接的调用 schedule() 来转换当前进程,而且上面已允许当前进程可被抢占。 //也就是说在处理完一轮软中断回调函数时,有可能会转换到其他进程。 cond_resched(); preempt_disable(); // 禁止当前进程被抢占。 rcu_sched_qs((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); // 判断当前进程是否会被停止,如果不是的话则设置进程状态为可中断状态并放弃当前 CPU 主动转换。 // 也就是说这里将一直等待当前进程将被停止时候才结束。 while (!kthread_should_stop()) { schedule(); set_current_state(TASK_INTERRUPTIBLE); } // 如果将会停止则设置当前进程为运行状态后直接返回。调度器会根据优先级来使当前进程运行。 __set_current_state(TASK_RUNNING); return 0;}
0 0
- 中断详解(七)——软中断与微任务
- 中断详解(二)——中断描述符、任务门、中断门、陷阱门
- 中断与任务——vxworks
- 中断与任务——vxworks
- 中断与任务——vxworks
- 中断详解(五)——中断处理程序
- 中断详解(四) ——异常与异常处理
- 中断—什么是中断
- 软中断与硬中断
- 软中断与硬中断
- 软中断与硬中断
- 软中断与硬中断
- ARM中断与软中断
- 软中断与硬中断
- 软中断与硬中断
- 软中断与硬中断
- 中断详解(一)——基本概念
- VxWorks任务调度与中断
- Matcher: find vs matches
- 让Static控件活起来
- spring 3 源代码构建
- [省选前题目整理][BZOJ 1297]迷路(矩阵快速幂)
- IplImage的使用 从三通道图中分离出三个单通道
- 中断详解(七)——软中断与微任务
- LeetCode--Unique Binary Search Trees II(DP求BST)
- [备忘] 命令行连接无线网 linux
- oracle for update和for update nowait的区别
- linux学习笔记
- list存list
- LINUX的IIC从这开始(一)
- 排序算法大总结(二)
- 从别人那里扒下来的一些有用的开发信息