进程线程中断的核心:栈
进程切换时,需要将当前进程的寄存器参数保存在当前进程的栈中。要再次执行此进程时需要先从栈中恢复此进程的寄存器参数。
对于同个进程的不同线程,代码和数据是所有线程共享的,所以线程间可以通过全局变量来传递数据。
Linuxs系统对中断处理的演进
Linux中的中断处理两个原则:1、原则上中断不能嵌套 2、中断处理越快越好
但当一个中断要耗费很多时间来处理时,它的坏处是:在这段时间内,其他中断无法被处理。换句话说,在这段时间内,系统是关中断的。 如果某个中断就是要做那么多事,我们能不能把它拆分成两部分:紧急的、 不紧急的?
所以可以将耗时分为上下半部,上半部处理紧急事件,系统关中断,不可被打断。下半部系统开中断可被打断。
下半部的实现方法很多,重要两种:1、tasklet(小任务)2、work queue(工作队列)
1、下半部要做的事情耗时不是太长:tasklet
当下半部比较耗时但是能忍受,并且它的处理比较简单时,可以用 tasklet 来处理下半部。tasklet 是使用软件中断来实现。
总结 :
- 中断的处理可以分为上半部,下半部
- 中断上半部,用来处理紧急的事,它是在关中断的状态下执行的
- 中断下半部,用来处理耗时的、不那么紧急的事,它是在开中断的状态下执行的
- 中断下半部执行时,有可能会被多次打断,有可能会再次发生同一个中断
- 中断上半部执行完后,触发中断下半部的处理
- 中断上半部、下半部的执行过程中,不能休眠:中断休眠的话,以后谁来调度进程啊?
2、下半部要做的事情太多并且很复杂:工作队列
在中断下半部的执行过程中,虽然是开中断的,期间可以处理各类中断。但是毕竟整个中断的处理还没走完,这期间 APP 是无法执行的。 假设下半部要执行 1 、 2 分钟,在这 1 、 2 分钟里 APP 都是无法响应的。
这谁受得了?所以,如果中断要做的事情实在太耗时,那就不能用软件中断来做,而应该用内核线程来做:在中断上半部唤醒内核线程。内核线程和 APP 都 一样竞争执行,APP 有机会执行,系统不会卡顿。
这个内核线程是系统帮我们创建的,一般是 kworker 线程,内核中有很多这样的线程:
kworker 线程要去“工作队列” (work queue) 上取出一个一个“工作” (work) ,来执行它里面的函数。
总结 :
⚫ 很耗时的中断处理,应该放到线程里去
⚫ 可以使用 work 、 work queue
⚫ 在中断上半部调用 schedule_work 函数,触发 work 的处理
⚫ 既然是在线程中运行,那对应的函数可以休眠。
3、新技术:threaded irq
只提供 thread_fn ,系统会为这个函数创建一个内核线程。发生中断 时,内核线程就会执行这个函数。
新技术 threaded irq ,为每一个中断都创建一个内核线程;多个中断的内核线程可以分配到多个 CPU 上执行,这提高了效率。