linux中断

中断体系

目的:

  1. 硬件的中断相应—>内核驱动中的中断
  2. 系统调用的函数相应(sys_call)—>系统调用
  3. 自定义中断–>软件的软中断模式
  4. 信号中断(kill -signanum) —>对了解信号的使用、创建等
  5. 系统的异常和错误—>系统的异常获取 了解系统异常的作用

Linux的中断机制

分类:硬中断、软中断

硬中断由电脑主句的8259A类似的硬件中断控制芯片发出 的中断, ARM中断控制器发出额中断
软中断异常 第一类:CPU自行保留的中断系统的调用异常

代码结构:

asm.strap.c
system_call.sfork.c signal.c sys.c exit.c

中断的工作流程:

2.1 做CPU工作模式的转化

进行寄存器的拷贝与压栈
设置中断异常向量表
保证正常运行的函数返回值
跳转到对应的中断服务函数上运行
进行模式的复原以及寄存器的复原
跳转回正常工作的函数地址继续运行

2.2 Linux中中断的工作流程:
  1. 将所有的寄存器值入栈:8086)SS EFLAGS ESP CS EIP (错误码) ARM中的(r0 ~ r15)
  2. 将异常码入栈(中断号)
  3. 将当前的函数返回值进行入栈(为了在中断执行后能够找到在哪里中断,能够复原)
  4. 调用对应的中断服务函数
  5. 出栈函数返回值
  6. 返回所有入栈的寄存器值

如图所示:

中断前的处理过程,中断的回复过程中断的执行过程
硬件中断的处理过程asm.strap.c
软件异常及系统调用的处理过程system_call.sfork.c signal.c sys.c
Created with Raphaël 2.3.0 将所有的寄存器值入栈 将异常码入栈 将当前的函数返回值进行入栈 调用对应的中断服务函数 返回所有入栈寄存器

中断的代码实现过程

中断前的处理过程,中断的回复过程中断的执行过程
硬件中断的处理过程asm.strap.c

中断下半部

把中断处理程序分为两部分:上半部(top half, th)和下半部(bottom half, bh)
上半部:在关闭中断的情况下执行,只做对时间非常敏感、与硬件相关或者不能被其他中断打断的工作
下半部:在开启中断的情况下执行,可以被其他中断打断
上半部称为硬中断(hardirq),下半部有3种:软中断(softirq)、小任务(tasklet)和工作队列(workqueue)。
3种下半部的区别如下:

  1. 软中断和小任务不允许睡眠;工作队列是使用内核线程实现的,处理函数可以睡眠
  2. 软中断的种类是编译时静态定义的,在运行时不能添加或删除;小任务可以在运行时添加或删除
  3. 同一种软中断的处理函数可以在多个处理器上同时执行,处理函数必须是可以重入的,需要使用锁保护临界区;一个小任务同一时刻只能在处理器上执行,不要求处理函数是可以重入的

软中断

软中断作为下半部机制的代表,是随着 SMP 的出现应运而生的,它也是tasklet实现的基础(tasklet实际上只是在软中断的基础上添加了一定的机制)。软中断一般是“可延迟函数”的总称,有时候也包括了tasklet(请读者在遇到的时候根据上下文推断是否包含tasklet)。它的出现就是因为要满足上面所提出的上半部和下半部的区别,使得对时间不敏感的任务延后执行,而且可以在多个CPU上并行执行,使得总的系统效率可以更高。特性是:
-> 产生后并不是马上可以执行,必须要等待内核的调度才能执行。软中断不能被自己打断,只能被硬件中断打断(上半部)。
-> 可以并发运行在多个CPU上(即使同一类型的也可以)。所以软中断必须设计为可重入的函数(允许多个CPU同时操作),因此也需要使用自旋锁来保护其数据结构。

小任务 tasklet

由于软中断必须使用可重入函数,这就导致设计上的复杂度变高,作为设备驱动程序的开发者来说,增加了负担。而如果某种应用并不需要在多个CPU上并行执行,那么软中断其实是没有必要的。因此诞生了弥补以上两个要求的tasklet。它具有以下特性:
-> 一种特定类型的tasklet只能运行在一个CPU上,不能并行,只能串行执行。
-> 多个不同类型的tasklet可以并行在多个CPU上。
-> 软中断是静态分配的,在内核编译好之后,就不能改变。但tasklet就灵活许多,可以在运行时改变(比如添加模块时)。
tasklet是在两种软中断类型的基础上实现的,因此如果不需要软中断的并行特性,tasklet就是最好的选择.
一般而言,在可延迟函数上可以执行四种操作:初始化/激活/执行/屏蔽。屏蔽我们这里不再叙述,前三个则比较重要。下面将软中断和tasklet的三个步骤分别进行对比介绍:

初始化

初始化是指在可延迟函数准备就绪之前所做的所有工作。一般包括两个大步骤:首先是向内核声明这个可延迟函数,以备内核在需要的时候调用;然后就是调用相应的初始化函数,用函数指针等初始化相应的描述符。

如果是软中断则在内核初始化时进行,其描述符定义如下:

 struct softirq_action   {
     void (*action)(struct softirq_action *);
     void *data;
 };

kernel/softirq.c 中的软中断描述符数组:static struct softirq_action softirq_vec[32]
前 6 个已经被内核注册使用:

  • tasklet 使用的 HI_SOFTIRQ
  • tasklet 使用的 TASKLET_SOFTIRQ
  • 网络协议栈使用的 NET_TX_SOFTIRQ
  • 网络协议栈使用的 NET_RX_SOFTIRQ
  • SCSI 存储
  • 系统计时器

其余的软中断描述符可以由内核开发者使用。

void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)

例如网络子系统通过以下两个函数初始化软中断(net_tx_action/net_rx_action是两个函数):

open_softirq(NET_TX_SOFTIRQ, net_tx_action);
open_softirq(NET_RX_SOFTIRQ, net_rx_action);

当内核中产生 NET_TX_SOFTIRQ 软中断之后,就会调用 net_tx_action 这个函数。
tasklet 则可以在运行时定义,例如加载模块时。定义方式有两种:

  • 静态声明
DECLARE_TASKET(name, func, data)
DECLARE_TASKLET_DISABLED(name, func, data)
  • 动态声明
void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data)

其参数分别为描述符,需要调用的函数和此函数的参数。初始化生成的就是一个实际的描述符,假设为 my_tasklet。

激活

激活:标记一个可延迟函数为挂起(pending)状态,表示内核可以调用这个可延迟函数。类似处于 TASK_RUNNING 状态的进程,处在这个状态的进程只是准备好了被 CPU 调度,但并不一定马上就会被调度。
软中断使用 raise_softirq() 函数激活,接收的参数就是上面初始化时用到的数组索引 nr。
tasklet 使用 tasklet_schedule() 激活,该函数接受 tasklet 的描述符作为参数,例如上面生成的 my_tasklet:

tasklet_schedule(&my_tasklet)
执行

执行就是内核运行可延迟函数的过程,但是执行只发生在某些特定的时刻。

每个CPU上都有一个32位的掩码__softirq_pending,表明此CPU上有哪些挂起(已被激活)的软中断。此掩码可以用local_softirq_pending()宏获得。所有的挂起的软中断需要用do_softirq()函数的一个循环来处理。

对于 tasklet,软中断初始化时设置了发生 TASKLET_SOFTIRQ 或 HI_SOFTIRQ 软中断时所执行的函数:

open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);

tasklet_action 和 tasklet_hi_action 内部实现不同,软中断和 tasklet 因此具有了不同的特性

工作队列

上面的可延迟函数运行在中断上下文中(如上章所述,软中断的一个检查点就是 do_IRQ 退出的时候),于是导致了一些问题:软中断不能睡眠、不能阻塞。由于中断上下文出于内核态,没有进程切换,所以如果软中断一旦睡眠或者阻塞,将无法退出这种状态,导致内核会整个僵死。但可阻塞函数不能用在中断上下文中实现,必须要运行在进程上下文中,例如访问磁盘数据块的函数。因此,可阻塞函数不能用软中断来实现。但是它们往往又具有可延迟的特性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值