中断和异常

承接已有博客

中断:异步中断,由其他硬件设备依照CPU时钟信号随机产生,比如间隔定时器和IO设备
异常:同步中断,当指令执行时由CPU控制单元产生的,即程序的错误产生的

中断描述符表IDT

和异常或中断向量相关联,映射向量对应的异常或中断处理程序的入口地址

  • 如何找到IDT:IDT在保护模式下可以在内存的任何位置,idtr寄存器里存放IDT的线性基地址及其限制
  • Linux利用中断门(清IF标志,不响应中断请求)处理中断,利用陷阱门(不修改IF标志)处理异常

门描述符

IDT里的表项也叫门描述符

上半部

响应中断后关键而紧急的部分,内核立即执行,关中断执行,中断处理程序

中断处理程序

响应一个特定中断时,内核执行的函数

  • 特点:
    • 无需重入,因为Linux允许嵌套中断,但不允许同一中断处理程序嵌套
    • 不允许睡眠(可以这样写,但理论上不应该允许睡眠),因为有时间限制
  • 简单的划分标准
    • 对时间非常敏感
    • 和硬件相关
    • 保证不被其他中断打断

下半部

响应中断后可以推迟的部分,内核随后执行,开中断执行。执行与中断处理密切相关但中断处理程序不执行的工作

  • 原因:
    • 中断处理程序(上半部)是异步执行,可能会打断其他重要进程,为了避免进程停止太久
    • 中断处理程序执行时,会关中断,执行时间长会影响其他中断
  • 处理时间:通常下半部在中断处理程序一返回就会马上运行

实现机制

软中断

静态定义的下半部接口,有32个

  • 特点:
    • 不允许睡眠
    • 可以在所有处理器上同时执行,即便类型相同
      • 需要自旋锁保护
      • 采用单处理器数据
      • 利用一些技巧避免显式加锁
      • 必须是可重入函数,即函数执行过程被中断,返回时不会出现问题
    • 用于性能需求比较高的情况
    • 用于执行频率很高的情况
    • 在编译期间静态注册
    • 只有中断处理程序抢占软中断
  • 执行时机
    • 从上半部返回
    • 显式检查待处理软中断
    • 在ksoftirq内核线程中
    • PS:一次完成固定数目的软中断,剩下的放入ksoftirq,避免用户进程饥饿得不到运行机会

tasklet

基于软中断(所以有软中断的基本特点)实现的的下半部接口,一般下半部使用tasklet

  • 特点:
    • 不允许睡眠
    • 类型不同的tasklet可以在不同处理器上同时执行,但是类型相同的tasklet不能同时执行
    • 可以通过代码动态注册
    • 不必为可重入函数

工作队列

把工作推后,交由一个内核线程去执行——这个下半部分总会在进程上下文中执行

  • 特点:
    • 允许重新调度或者睡眠
      • 这也是选择软中断tasklet还是选择工作队列需要考虑的
    • 每个处理器对应一个内核线程
    • 也是一次执行所有延迟工作
    • 链表上有对象,状态设为TASK_RUNNING;链表上没有对象了,状态设为TASK_INTERRUPTIBLE

do_softirq函数

处理固定个数的软中断,过量软中断交给ksoftirq线程

ksoftirqd内核线程

执行软中断的一个内核线程,每个CPU都有自己的

  • 解决的问题:比如网卡上数据报泛滥会高频率激活软中断,即过量软中断造成用户进程饥饿无法运行
  • 解决策略:do_softirq把过量的软中断交给ksoftirq线程

有关内核栈

  1. 如果内核栈是8KB,那么当前被中断进程的内核栈被用作中断栈
  2. 如果内核栈是4KB,内核就使用3种类型的内核栈
    • 异常栈:用于处理异常,比如系统调用。共用内核栈
    • 硬中断请求栈:用于处理中断,每个CPU一个,4KB
    • 软中断请求栈:用于处理下半部,每个CPU一个,4KB
posted @ 2021-02-09 23:18  肥斯大只仔  阅读(100)  评论(0编辑  收藏  举报