Linux中断下半部实现机制
1. 中断上、下半部产生背景
由于内核中中断不允许嵌套,在程序进入中断后,系统会关闭中断接收,这段时间内,其他中断都无法处理导致中断无法响应,因此需要当前进入的中断子服务函数越快越好。但是在一些特殊情况下,中断要处理的事情可能是复杂且冗长的,为解决这种问题, 中断上下半部的概念顺势而生。将中断拆成两部分,上半部用来处理紧急的事情;下半部用来处理不紧急的事情。
2. 运行机制
(1) tasklet方式: 当下半部处理的事情耗时但是可以忍受时,可以使用tasklet。tasklet是以软中断形式实现的,软中断的优先级仅次于硬件中断,在进入软件中断时,硬件中断会被打开,因此软件中断可被硬件中断打断。 使用: 软中断实现服务子函数,优先级高,影响系统执行效率。 a. 初始化:
静态(编译时创建):
DECLARE_TASKLET(kpd_keymap_tasklet, kpd_keymap_handler, 0);
动态(在函数probe或其他入口函数初始化):
struct tasklet_struct kpd_keymap_tasklet;
tasklet_init(&kpd_keymap_tasklet, kpd_keymap_handler, 0);
b. 下半部实现:
static void kpd_keymap_handler(unsigned long data)
{
}
c. 在硬件中断服务函数,调度:
tasklet_schedule(&kpd_keymap_tasklet);
d. 在退出函数,销毁:
tasklet_kill(&kpd_keymap_tasklet);
(2) 工作队列方式: 在tasklet方式中,虽然开中断了,期间可处理系统各种中断,但是软中断的优先级也会导致其他的线程无法运行。如果时间过长,会导致系统卡顿且APP也无法运行的现象。此时选择内核线程来处理下半部:在中断上半部将下半部处理函数放入工作队列,且唤醒工作队列线程,然后退出中断。包含下半部的工作队列与APP都有机会执行,不会造成卡顿。 使用: 一个工作线程处理多个中断服务子函数。 a. 初始化
静态:
DECLARE_WORK(my_work, my_func, &data);
动态:
struct work_struct my_work;
INIT_WORK(&my_work, my_func, &data);
b. 下半部实现
void my_func()
{
}
c. 在硬件中断调度
schedule_work(&my_work); //工作完成后会自动销毁
注意: 也可以自定义工作队列,实现任务调度,这里不作介绍。
(3) 线程中断:由于工作队列每次只能处理一个中断下半部,但是内核支持多线程,因此出现为每一个中断下半部开辟一个线程处理。将多个中断的下半部线程分配给多个CPU上执行,提高效率。 使用: 一个线程对应一个中断服务子函数,效率高,占用资源。 在程序中调用request_threaded_irq
原型:
/* irq: 中断号
* handler: 中断服务子函数
* thread_fn: 中断线程化
* irqflags: 中断触发标志位
* devname: 请求中断的设备名称
* dev_id: 传递给thread_fn参数,通常为设备结构体
*/
int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn,
unsigned long irqflags, const char *devname, void *dev_id);
实例:
int request_threaded_irq(irq, isr, my_func, IRQF_TRIGGER_FALLING, "key_isr", &key_quest[i]);
下半部:
static irqreturn_t my_func (int irq, void *data)
{
……
return IRQ_HANDLED;
}
中断服务子函数:
static irqreturn_t isr(int irq, void *dev_id)
{
……
return IRQ_WAKE_THREAD;
}
触发流程: 先进入中断服务子函数handler 返回IRQ_WAKE_THREAD,然后会进入线程化中断my_func。 每个中断都会对应一个线程,互不干扰,效率更高。
- 柴毛毛大话设计模式——开发常用的设计模式梳理
- Redis源码分析(四)——Redis数据结构-整数集合
- Redis源码分析(三)——Redis数据结构-字典
- Redis源码分析(二)——Redis数据结构-链表
- C++实现神经网络之一 | Net类的设计和神经网络的初始化
- Redis源码分析(一)——Redis数据结构-字符串SDS
- 使用RNN预测股票价格系列二
- 微软 WCF的几种寄宿方式,寄宿IIS、寄宿winform、寄宿控制台、寄宿Windows服务
- 深度学习框架之一:Theano | Lasagne简单教程
- 有趣的应用 | 使用RNN预测股票价格系列一
- 通过深度学习实现安全帽佩戴的检测
- python及numpy,pandas易混淆的点
- 深度学习中的损失函数总结以及Center Loss函数笔记
- TF使用例子-LSTM实现序列标注
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- python第四课——运算符
- python第五课——流程控制语句
- LNMP架构应用实战—Nginx反向代理负载均衡配置
- python第六课——判断结构
- MySQL数据库入门——备份数据库
- python第七课——循环结构 while
- python第八课——random模块的使用
- python第九课——while死循环
- python第十课——循环结构收尾
- python第十二课——for in循环
- Linux系统实战——批量无人值守安装操作系统
- python第十三课——嵌套循环
- python第十四课--排序及自定义函数
- python第十四课--排序及自定义函数之案例一:选择排序
- python第十四课--排序及自定义函数之案例二:冒泡排序