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是异步发送的,所以内核必须禁止它们。

时间: 2024-08-15 21:31:14

Linux内核中的中断的相关文章

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

转自:http://blog.chinaunix.net/uid-12461657-id-3487463.html 原文地址:Linux内核中的中断栈与内核栈的补充说明 作者:MagicBoy2010 中断栈与内核栈的话题更多地属于内核的范畴,所以在<深入Linux设备驱动程序内核机制>第5章“中断处理”当中,基本上没怎么涉及到上述内容,只是在5.4节有些许的文字讨论中断栈在中断嵌套情形下可能的溢出问题. 本贴在这个基础上对内核栈与中断栈的话题做些补充,讨论基于x86 32位系统,因为64位系

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

本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内核中添加外部中断驱动模块.7.完整驱动程序代码.linux的内核版本为linux2.6.32.2. 一.linux模块的框架以及混杂设备相关知识 1.内核模块的框架如下图所示,其中module_init()(图中有误,不是modules_init)只有在使用insmod命令手动加载模块时才会被调用,

linux内核学习:中断中推后执行的部分

软中断-softirq 特点 相同和不同的软中断都可以在不同处理器上同时执行 一个软中断不会抢占另一个软中断 何时执行 从中断程序返回时 ksoftirqd线程中 显示调用 软中断最多有32个,一个32位的整型数据可以被用来标记刮起的软中断 使用策略 软中断应用于确实需要的场合,目前只有网络驱动和SCSI驱动中使用.另外,内核定时器和tasklet建立在软中断之上. 使用方法 注册软中断 void open_softirq(int nr, void (*action)(struct softir

Linux内核中的jiffies及其作用介绍及jiffies等相关函数详解

在LINUX的时钟中断中涉及至二个全局变量一个是xtime,它是timeval数据结构变量,另一个则是jiffies,首先看timeval结构struct timeval{time_t tv_sec; /***second***/susecond_t tv_usec;/***microsecond***/}到底microsecond是毫秒还是微秒?? 1秒=1000毫秒(3个零),1秒=1000 000微秒(6个零),1秒=1000 000 000纳秒(9个零),1秒=1000 000 000

Linux内核中的软中断、tasklet和工作队列详解

[TOC] 本文基于Linux2.6.32内核版本. 引言 软中断.tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的"下半部"(bottom half)演变而来.下半部的机制实际上包括五种,但2.6版本的内核中,下半部和任务队列的函数都消失了,只剩下了前三者. 介绍这三种下半部实现之前,有必要说一下上半部与下半部的区别. 上半部指的是中断处理程序,下半部则指的是一些虽然与中断有相关性但是可以延后执行的任务.举个例子:在网络传输中,网卡接收到数据包这

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

转载:http://www.cnblogs.com/leaven/archive/2010/08/06/1794293.html 更多文档参见:http://pan.baidu.com/s/1dDvJRaD 作者:刘洪涛,华清远见嵌入式学院金牌讲师,ARM ATC授权培训讲师. 看了一些网络上关于linux中断实现的文章,感觉有一些写的非常好,在这里首先感谢他们的无私付出,然后也想再补充自己对一些问题的理解.先从函数注册引出问题吧. 一.中断注册方法 在linux内核中用于申请中断的函数是req

linux内核学习:中断

编程相关 注册中断 int request_irq( unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) typedef irqreturn_t (*irq_handler_t)(int, void *); IRQF_DISABLED 会禁用除本本身以外的其它中断,一般是不用的 IRQF_SAMPLE_RANDOM 可以帮助内核随机数的产生.如果中断产生地毫无规律,可

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

linux内核中内存相关的操作函数 1.kmalloc()/kfree() static __always_inline void *kmalloc(size_t size, gfp_t flags) 内核空间申请指定大小的内存区域,返回内核空间虚拟地址.在函数实现中,如果申请的内存空间较大的话,会从buddy系统申请若干内存页面,如果申请的内存空间大小较小的话,会从slab系统中申请内存空间.有关buddy和slab,请参见<linux内核之内存管理.doc> gfp_t flags 的选项

大话Linux内核中锁机制之原子操作、自旋锁

转至:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 很多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实是由于操作系统中存在多进程对共享资源的并发访问,从而引起了进程间的竞态.这其中包括了我们所熟知的SMP系统,多核间的相互竞争资源,单CPU之间的相互竞争,中断和进程间的相互抢占等诸多问题. 通常情况下,如图1所示,对于一段程序,我们的理想是总是美好的,希望它能够这样执行:进程1先对临界区完成操作,