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内核中的中断的更多相关文章

  1. Linux内核中的中断栈与内核栈的补充说明【转】

    转自:http://blog.chinaunix.net/uid-12461657-id-3487463.html 原文地址:Linux内核中的中断栈与内核栈的补充说明 作者:MagicBoy2010 ...

  2. 向linux内核中添加外部中断驱动模块

    本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内 ...

  3. Linux内核中的GPIO系统之(3):pin controller driver代码分析

    一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道,pin control subsystem也不例外,被它驱动的硬件叫做pin controller(一般ARM soc的datash ...

  4. 【转】 Linux内核中读写文件数据的方法--不错

    原文网址:http://blog.csdn.net/tommy_wxie/article/details/8193954 Linux内核中读写文件数据的方法  有时候需要在Linuxkernel--大 ...

  5. Linux内核中SPI总线驱动分析

    本文主要有两个大的模块:一个是SPI总线驱动的分析 (研究了具体实现的过程): 另一个是SPI总线驱动的编写(不用研究具体的实现过程). 1 SPI概述 SPI是英语Serial Peripheral ...

  6. linux-2.6.26内核中ARM中断实现详解(转)

    转载:http://www.cnblogs.com/leaven/archive/2010/08/06/1794293.html 更多文档参见:http://pan.baidu.com/s/1dDvJ ...

  7. Linux内核中的软中断、tasklet和工作队列具体解释

    [TOC] 本文基于Linux2.6.32内核版本号. 引言 软中断.tasklet和工作队列并非Linux内核中一直存在的机制,而是由更早版本号的内核中的"下半部"(bottom ...

  8. (笔记)Linux内核中内存相关的操作函数

    linux内核中内存相关的操作函数 1.kmalloc()/kfree() static __always_inline void *kmalloc(size_t size, gfp_t flags) ...

  9. 进程在Linux内核中的角色扮演

    在Linux内核中,内核将进程.线程和内核线程一视同仁,即内核使用唯一的数据结构task_struct来分别表示他们:内核使用相同的调度算法对这三者进行调度:并且内核也使用同一个函数do_fork() ...

随机推荐

  1. Html5+Css3 Banner Animation 多方位移动特效

    背景:朋友问我小米官网的mi4的特效会做吗,可能新接的一个小网站需要用到.一直有打算研究H5C3的一些效果,趁此机会,赶紧学习一下! 效果:如图 素材 HTML: <div class=&quo ...

  2. 【转】简单理解socket

    题外话 前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公司使用的一些控件的开发,浏览器兼容性搞死人:但主要是因为这段时间一直在看html5的东西,看到web socket时觉得很有 ...

  3. UVaOJ 120 - Stacks of Flapjacks

    120 - Stacks of Flapjacks 题目看了半天......英语啊!!! 好久没做题...循环输入数字都搞了半天...罪过啊!!! 还是C方便一点...其实C++应该更方便的...C+ ...

  4. ajax 内部值 外部调用不了原因

    var id=‘123’; $.ajax({ url:’http://www.xxx.com/ajax', type:'post', dataType: "json", data: ...

  5. netty启动过程

    netty先启动work线程,work线程打开selector 绑定pipeline 启动boss线程,绑定端口,注册selector,绑定op_accetp事件 ------------------ ...

  6. 获取当前<script>节点

    /* get current JavaScript dom object. */ var all_js = document.getElementsByTagName("script&quo ...

  7. present的时候是可以直接回到第一个viewcon的

    最新:我并没有记错,是可以直接回到的 [self.presentingViewController.presentingViewController dismissModalViewControlle ...

  8. php header函数要点

    发布:snowfly   来源:网络     [大 中 小] 相信很多人写程序时,使用 header(location) 进行跳转往往不记得写 exit() 语句,这种做法存在严重风险. 从浏览器来看 ...

  9. php mysqli多个查询的例子

    php中Mysqli多个查询的例子,感兴趣的朋友可以参考下. php中Mysqli多个查询的例子,感兴趣的朋友可以参考下. mysqli_multi_query(mysqli link,string ...

  10. nginx如何实现404状态返回 200隐藏URL

    以http://WWW.cnblogs.COM为例: server        {                listen       80;                server_nam ...