Linux内核中的中断
http://blog.csdn.net/weiqing1981127/article/details/8298585
中断处理程序是被内核调用来响应中断的,它运行在中断上下文,中断处理程序是上半部,当接收到一个中断,它就立即开始执行,但只做有严格时限的工 作,例如对接收的中断进行应答或复位硬件,这些工作都是在所有中断被禁止的情况下完成。能够被允许稍后完成的工作会推迟到下半部去。
中断处理程序的注册是通过request_irq函数,由于该函数内部有分配内存的操作,所以它不能在中断上下文或其他不允许阻塞的代码中调用。Linux中的中断处理程序是无须重入的,因为当一个给定的中断处理程序正在执行时,所有其他的中断都是打开的,而当前中断线总是被禁止的,由此可见,同一个中断处理程序绝不会被同时调用以处理嵌套的中断。中断处理程序不用关心中断栈和内核栈的设置,尽量节约内核栈空间就是了。
锁提供保护机制,防止来自其他处理器的并发访问,而禁止中断提供的保护机制则是防止来自其他中断处理程序的并发访问。禁止中断包括禁止当前处理器的所有中断和禁止一条中断线两种,禁止所有中断可以使用local_irq_save和local_irq_restore函数,禁止一个中断线可以使用disable_irq函数。
查看使用的中断号可以用cat /proc/interrupts得到。中断系统的状态可以通过几个函数获得,irqs_disabled函数查看本地中断传递是否被禁止;in_interrupt函数查看是否在中断上下文;in_irq查看是否是当前正在执行中断处理程序。
为什么要引入下半部呢?因为中断处理流程的上半部有一些局限:其一,中断以异步方式执行,它有可能打断其他重要代码,为了避免打断时间过长,中断处 理程序应该执行的快些。其二,如果当前有一个中断处理程序正在执行,需要做一个禁止其他中断的操作,禁止中断后硬件和操作系统无法通信了,所以也有中断处 理快点。其三,中断处理往往需要对硬件操作,所以也需要快点。其四,中断处理程序不在进程上下文,不能睡眠,这也限制了它们所做的事。
下半部的任务就是执行与中断处理密切相关中断处理程序本身不执行的工作。中断处理程序往往需要通过操作硬件对中断的到达进行确认,有时它还会从硬件 拷贝数据。我们将对时间非常敏感,与硬件相关,要保证不被其他中断打断的事情放在中断处理程序中执行,其他任务考虑放到下半部执行。下半部执行的关键在于 当它们运行的时候,运行相应所有的中断。
在2.6内核版本中,下半部实现的机制包括软中断、tasklet和工作队列。
软中断是一组静态定义的下半部接口,有32个,可以在所以处理器上同时执行,软中断必须在编译期间就进行静态注册,这里的软中断不是系统调用中提到的软中断。软中断在下面地方会被执行:其一,一个硬件中断代码处返回时。其二,在ksoftirqd内核线程中(每个处理器都有一组辅助处理软中断和tasklet的内核线程,当大量软中断出现时,内核会唤醒一组内核线程来处理这些负载,这个内核线程就是ksoftirqd线程)。其三,在那些显式检查和执行处待理的软件中断的代码中,如网络子系统。只有网络和SCSI子系统直接使用软中断,对于世界要求严格并能自己高效地完成加锁工作的应用,软中断是正确的选择。
tasklet有两种类软中断代表:HI_SOFTIRQ和TASKLET_SOFTIRQ,前者优先级更高。所有的tasklet都通过重复运用HI_SOFTIRQ和TASKLET_SOFTIRQ这两个软中断实现。当一个tasklet被调用时,内核就会唤醒这两个软中断中的一个,随后该软中断会被特定的函数处理,执行所有已调度的tasklet,这个函数保证同一时间里只有一个给定类别的tasklet会被执行。Tasklet不能睡眠,这意味着你不能在tasklet中使用信号量或其他什么阻塞式的函数,同时由于tasklet运行时允许响应中断,所以你必须做好预防(如屏蔽中断然后获得一个锁),另外,你可以调用tasklet_disable函数禁止某个指定的tasklet,你也可以使用tasklet_kill从挂起队列中去掉一个tasklet。
DECLARE_TASKLET(test_tasklet,test_tasklet_func,0); //定义
void test_tasklet_func(void) //处理函数
{
printk("tasklet is executing!\n");
}
tasklet_schedule(&test_tasklet); //调度
工作队列可以把工作推后,交给一个内核线程去执行,这个下半部分总是会在进程上下文中执行,工作队列运行重新调度甚至是睡眠,它是唯一能在进程上下 文中运行的下半部实现机制,也只有它可以睡眠。尽管操作处理函数运行在进程上下文,但它不能访问用户空间,因为内核线程在用户空间没有相关的内存映射,通 常只有发生系统调用时,内核才会代表用户空间的进行运行。
工作队列子系统提供了一个缺省的工作者线程,我们只要把需要推后执行的任务交给特定的通用线程就好了,缺省的工作者线程叫events/n,我们一般使用这个缺省的工作者线程,但是如果你需要在工作者线程中执行大量的处理操作,创建自己的工作者线程就更好了。系统的每个CPU都会有一个工作者线程,每个工作者线程都是由struct cpu_workqueue_struct结构体表示,而struct workqueue_struct则表示给定类型(即同类型)的所有工作者线程。
INIT_WORK(&button_dev->work, gpio_keys_report_event); //定义
static void gpio_keys_report_event(struct work_struct *work) //处理函数
{
key_values[0] = '0' ; //清除按键标识
input_report_key(channel, BTN_0, !!ev_press); //向input子系统报告按键事件
input_sync(channel); //同步操作
ev_press = 0; //清除按键值
}
schedule_work(&button_dev->work); //调度工作队列处理函数
cancel_work_sync(&button_dev->work); //删除工作队列
tasklet基于软件中断,而工作队列是靠内核线程实现的,如果你有休眠的需要,那么你使用工作队列,否则最好使用tasklet机制。为了保证共享数据,一般先得到一个锁,然后使用local_bh_disable函数禁止下半部,但local_bh_disable函数并不能禁止工作队列的执行,因为工作队列不涉及异步执行,但是由于软中断和tasklet是异步发送的,所以内核必须禁止它们。
Linux内核中的中断的更多相关文章
- Linux内核中的中断栈与内核栈的补充说明【转】
转自:http://blog.chinaunix.net/uid-12461657-id-3487463.html 原文地址:Linux内核中的中断栈与内核栈的补充说明 作者:MagicBoy2010 ...
- 向linux内核中添加外部中断驱动模块
本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内 ...
- Linux内核中的GPIO系统之(3):pin controller driver代码分析
一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道,pin control subsystem也不例外,被它驱动的硬件叫做pin controller(一般ARM soc的datash ...
- 【转】 Linux内核中读写文件数据的方法--不错
原文网址:http://blog.csdn.net/tommy_wxie/article/details/8193954 Linux内核中读写文件数据的方法 有时候需要在Linuxkernel--大 ...
- Linux内核中SPI总线驱动分析
本文主要有两个大的模块:一个是SPI总线驱动的分析 (研究了具体实现的过程): 另一个是SPI总线驱动的编写(不用研究具体的实现过程). 1 SPI概述 SPI是英语Serial Peripheral ...
- linux-2.6.26内核中ARM中断实现详解(转)
转载:http://www.cnblogs.com/leaven/archive/2010/08/06/1794293.html 更多文档参见:http://pan.baidu.com/s/1dDvJ ...
- Linux内核中的软中断、tasklet和工作队列具体解释
[TOC] 本文基于Linux2.6.32内核版本号. 引言 软中断.tasklet和工作队列并非Linux内核中一直存在的机制,而是由更早版本号的内核中的"下半部"(bottom ...
- (笔记)Linux内核中内存相关的操作函数
linux内核中内存相关的操作函数 1.kmalloc()/kfree() static __always_inline void *kmalloc(size_t size, gfp_t flags) ...
- 进程在Linux内核中的角色扮演
在Linux内核中,内核将进程.线程和内核线程一视同仁,即内核使用唯一的数据结构task_struct来分别表示他们:内核使用相同的调度算法对这三者进行调度:并且内核也使用同一个函数do_fork() ...
随机推荐
- javascript 基础API
Math.random() 取值范围[0,1) 大于等于0小于1,包括0,不包括1 Math.floor() 向下取整 Math.ceil() 向上取整 第一题:一组数的规则如下:1.1.2.3. ...
- Adapter模式
Adapter模式主要用于将一个类的接口转换为另外一个接口,通常情况下再不改变原有体系的条件下应对新的需求变化,通过引入新的适配器类来完成对既存体系的扩展和改造.实现方式主要包括: 1.类的Adapt ...
- HP平台由于变量声明冲突导致程序退出时的core
最近遇到一个莫名的问题,在HP-UX B.11.31 U ia64平台下,程序PetriService在接收到产品化退出或Ctrl-C时,程序在main函数返回后析构全局的CTQueue<SMs ...
- Libcurl笔记一
一:1,全局初始化及释放:CURLcode curl_global_init(long flags) flags: CURL_GLOBAL_ALL //初始化所有的可能的调用. CURL_GLOBAL ...
- python pil 安装
Ubuntu下 sudo pip install pil 安装PIL可能会出现问题,例如安装完成时显示JPEG support not available 或者 ZLIB (PNG/ZIP) supp ...
- mysql安装启动教程(两种方法)
mysql安装启动: 方法一(简单版): cmd进入mysql安装的bin目录:mysqld.exe –install net start mysql 服务启动(或者选择计算机->(右键)管理 ...
- 条形码Code128源代码
public class Code128 { private DataTable m_Code128 = new DataTable(); ; /// <summary> /// 高度 / ...
- DTcms会员中心添加新页面-会员投稿,获得所有文章并分页
DAL.article.cs /// <summary> /// 自定义:获得查询分页数据 /// </summary> public DataSet GetList(int ...
- 怎么在spring官网上下载spring的jar包, 源代码和文档?
现在 http://repo.spring.io/release/org/springframework/spring/第一种,简单粗暴直接 1 http://repo.springsource.or ...
- 百度地图API实现多区域标记
最近遇到一个业务就是需要需要在地图上标记多个区域.一般餐饮业做外卖的,配送范围一般是多区域的,那么在地图上标记配送范围的时候就需要能标记多个区域.长话短说,最初的实现原型的截图如下: