2021-10-24

8.下半部和推后执行的工作

下半部机制:内核中所有将工作推迟的机制都叫下半部机制
1.中断处理程序以异步方式执行,并可能打断其他代码
2.不能消耗太长时间
3.中断处理不在进程上下文中运行,所以不能阻塞
所以一般将时间敏感的操作硬件的不可被中断的程序放在(中断处理程序)上半部中

下半部的重要性

为了缩短中断处理程序的响应时间及其他程序被屏蔽的时间,如果系统不太繁忙,一般上半部返回时就立即执行下半部

8.1.2 下半部的环境

BH:它提供了一个静态创建,由32个bottem harves组成的链表,上半部提供一个数来确定执行哪个,此机制在所有cpu上只能运行一个中断
任务队列:内核定义了一组队列来挨个执行函数组成的链表,此机制用来代替BH
软中断和tacklst:软中断是静态定义的32个下半部接口,可以在多个cpu上同时运行相同/不同的中断;不同类型的tacklst可在不同处理器上同时运行,相同类型就不可以

8.2 软中断

软中断在编译期间是静态分配https://www.cnblogs.com/zhxshseu/p/5293979.html
软中断不会抢占软中断,它只能被中断处理程序抢占,最多有32个软中断
触发软中断指软中断被标记后才能执行
在每个处理器上单独的地址空间运行中断,避免资源加锁
https://www.sohu.com/a/216557079_236714

8.3 tacklst实现

tacklst是用tasklst结构体实现,结构体被放在一个链表中,每个结构体都是一个tasklst,tacklst是动态分配,tacklst是用软中断实现的
4.ksoftirqd:当内核出现大量软中断时,cpu将被中断处理程序占满,ksoftirqd是用来处理这些大量软中断的。
如果内核忙于处理中断程序,用户就会陷入饥饿,反之内核陷入饥饿,ksoftirqd做一个折中:每个cpu上会有一个内核线程,在最低的优先级上运行,通过死循环保证只要有空闲的处理器就会处理软中断
内核饥饿:把自行触发的软中断放到下一次中断返回之后去处理,确保及时响应用户
用户饥饿:软中断可能会在执行时重新触发自己使自己再次得到执行,立即处理会造成cpu负载过重

8.4 工作队列

可以把工作推后,交给一个内核线程执行,这个下半部总会在进程上下文中执行,所以可以睡眠,所以需要睡眠的任务,就给工作队列,不需要睡眠的就给软中断/tacklst
工作队列子系统可以创建一个内核线程接口,用来执行排队的线程,这些线程叫做工作者线程,一般由缺省的工作者线程来处理,处理器密集型任务会有自己的工作者线程,确保性能

工作队列的结构

所有工作者线程在一个workqueue_struct结构体中,结构体内有一个数组对应着很多处理器和很多工作者线程,每个工作者线程用cpu_workqueue_struct()表示,同时对应一个链表,每个链表节点有一个work_struct死循环实现,链表都处理完时就休眠

8.5 下半部机制的选择

1.软中断:需要采取一些步骤保证共享数据安全,如果完全使用单处理器变量,那么软中断就很好
2.tasklet:本质上就是用软中断实现的,实现起来更简单,不能并发运行,保证了资源安全,性能比软中断差一点
3.工作队列:如果需要睡眠,就用工作队列,此机制实现简单,开销也最大,因为涉及到上下文切换和内核线程

8.7 禁止下半部

为了保护内存资源可能要先得到一个锁然后禁止下半部执行