linux中断底半部机制对比(任务队列,工作队列,软中断)--由linux RS485引出的血案-ispsubb-ChinaUnix博客
Linux中的中断概念以及处理方式--中断上下半部等
Linux中的中断概念以及处理方式--中断上下半部等与Linux设备驱动中中断处理相关的首先是申请与释放IRQ的API request_irq()和free_irq(),request_irq()的原型为:int request_irq(unsigned int irq,void (*handler)(int irq, void *dev_id, struct pt_regs *regs),unsigned long irqflags,const char * devname,void *dev_id);irq是要申请的硬件中断号;handler是向系统登记的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递;irqflags是中断处理的属性,若设置SA_INTERRUPT,标明中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置SA_SHIRQ,则多个设备共享中断,dev_id在中断共享时会用到,一般设置为这个设备的device结构本身或者NULL。
free_irq()的原型为:void free_irq(unsigned int irq,void *dev_id);另外,与Linux中断息息相关的一个重要概念是Linux中断分为两个半部:上半部(tophalf)和下半部(bottom half)。
上半部的功能是"登记中断",当一个中断发生时,它进行相应地硬件读写后就把中断例程的下半部挂到该设备的下半部执行队列中去。
因此,上半部执行的速度就会很快,可以服务更多的中断请求。
但是,仅有"登记中断"是远远不够的,因为中断的事件可能很复杂。
因此,Linux引入了一个下半部,来完成中断事件的绝大多数使命。
下半部和上半部最大的不同是下半部是可中断的,而上半部是不可中断的,下半部几乎做了中断处理程序所有的事情,而且可以被新的中断打断!下半部则相对来说并不是非常紧急的,通常还是比较耗时的,因此由系统自行安排运行时机,不在中断服务上下文中执行。
Linux26内核中下半部分分析解析
目录
• 简介 • 历史&发展 • 实现机制
• • • 软中断 Tasklet 工作队列(new)
• 总结
bottom half(BH)
BH接口非常简单,它提供一个静态创建、 由32个bottom half组成的链表。上半部分 通过一个32位整数中的一位来识出哪个 bottom half可以执行。每个BH都在全局范 围内进行同步。即使分属于不同的处理器, 也不允许两个bottom half同时执行。 使用不灵活,大大降低多处理器的性能。
work quque
从2.5开始,BH接口最终被弃置,任务队列被 工作队列(work queue)接口取代。工作 队列可以把工作推后,交由一个内核线程 去执行—这个下半部分总会在进程上下文 执行。工作队列允许重新调度甚至睡眠。
2.6版本中,内核提供了三种不同形式的下 半部分实现机制:软中断、tasklet和工作队 列。
目录
• 简介 • 历史&发展 • 实现机制
• • • 软中断 Tasklet 工作队列(new)
q_action结构表示,定义在 <include/linux/interrupt.h>中。
Kernel/softirq.c中定义了一个包含有32个 softirq_action数组。每个被注册的软中断都 占据该数组中的一项,最多可有32个软中 断,2.6.24.1内核中可使用其中的8个。
线程的数据结构
• 结构中有一个cpu_workqueue_struct结构 组成的数组,每一项对应一个处理器。由 于每个处理器对应一个工作者线程,所以 对单台计算机来说,每个工作者线程对应 一个这样的cpu_workqueue_struct结构体。
所有的工作者线程都是用普通的内核线程 实现的,它们都要执行worker_tread().在它 初始化完以后,这个函数执行一个列循环 并开始休眠。当有操作被插入到队列里的 时候,线程就会被唤醒,以便执行这些操 作。当没有剩余的操作时,它又会继续休 眠。
Linux内核中断处理机制
Linux内核中断处理机制<什么是中断>计算停下当前处理任务,并保存现场,转⽽去处理其他是任务,当完成任务后再回到原来的任务中去。
<中断的分类>a:软中断软中断时执⾏中断指令产⽣的,软中断不⽤施加中断请求信号,因此中断的产⽣的不是随机的⽽是由程序安排的。
内核线程是实现软中断的助⼿。
b:硬中断硬中断时由外部硬件产⽣的,具有随机性。
<中断的实现>int request_irq(unsigned int irq,irq_handler_t handler,unsigned long intflags,const char devname, void *dev_id)解释:irq:申请的中断号。
handler:中断处理函数指针irqflags:中断处理属性,与上半段和下半段有关系devname:中断设备名字dev_id:与共享中断号有关系。
注:该函数的主要作⽤是在内核中的⼀个重要的结构体"irq_desc"中注册中断号与对应的中断处理函数。
<释放中断线>void free_irq(unsigned int irq ,void dev_id);注:⼀般操作硬件的端⼝都会调⽤ioremap()函数,该函数⽤来将计算实际的物理地址映射成虚拟地址,这样系统才能访问。
<中断处理机制之上半部分和下半部>a:Linux中中断处理是⼀种很霸道的东西,只要没有屏蔽中断,CPU就会⽴即相应。
为了加开处理的数据,Linux中通常将中断处理中的硬件相关的操作放在上半部分,耗时的操作放在下半部分——linux 内核⼀般将中断处理分为两不份:上半部(top_half)和下半部(bottom_half)。
b:上半部分⼀般调⽤中断处理函数,⼀进⼊中断处理函数就是进⾏相应的硬件操作,这些都是放在上半部分。
然后将耗时的操作放在下半部分中。
c:下半部分Linux中实现下半部分的处理有:softirq机制,tasklist机制(⼩任务⽚段),workqueue机制----tasklet将任务延迟到安全时间执⾏,每个tasklet都和⼀个函数相关联,当tasklet运⾏时,----该函数就被调⽤,并且tasklet可以调度⾃⼰。
linux中断处理上半部下半部实例
linux中断处理上半部下半部实例Linux中断处理是操作系统中的重要概念之一,它负责处理外部设备发出的中断信号。
中断处理分为上半部和下半部,两者分别对应着紧急任务和延后处理任务。
本文将通过一个实例来详细介绍Linux中断处理的上半部和下半部。
在Linux系统中,中断是指外部设备向处理器发出的请求,要求处理器立即暂停当前的工作,转而去执行与该中断相关的处理程序。
中断的发生可以是硬件产生的,也可以是软件产生的。
无论是硬件中断还是软件中断,处理方式都遵循相同的原则,即中断处理程序分为上半部和下半部。
上半部是中断处理程序的核心部分,也是最紧急的部分。
当中断发生时,处理器首先执行上半部的代码。
上半部主要负责处理与中断直接相关的任务,如保存寄存器状态、处理中断请求、更新相关数据等。
上半部的执行时间应尽量短,因为在中断期间,处理器无法执行其他任务。
如果上半部执行时间过长,会导致系统响应缓慢,甚至影响其他紧急任务的执行。
下半部是中断处理程序的延后处理部分。
当上半部完成后,处理器会立即执行下半部的代码。
下半部主要负责一些较为复杂或耗时较长的任务,如更新数据结构、发送信号、唤醒进程等。
相比于上半部,下半部的执行时间可以更长一些,因为在执行下半部的同时,处理器可以继续执行其他任务。
为了更好地理解上半部和下半部的关系,我们可以以网络设备驱动程序为例。
当网络设备接收到数据包时,会触发一个中断信号。
操作系统会立即执行中断处理程序,即上半部。
在上半部中,操作系统会将接收到的数据包拷贝到内存中,并更新相关的数据结构。
然后,操作系统会调度一个延后处理的任务,即下半部,来进一步处理接收到的数据包。
下半部可以对数据包进行进一步的解析、处理和分发。
通过上下半部的协作,网络设备驱动程序可以高效地处理接收到的数据包,并及时地通知上层应用程序。
除了网络设备驱动程序,中断处理也广泛应用于其他领域。
比如,在实时系统中,中断处理可以用于处理实时事件,如传感器数据的采集、控制信号的发送等。
软中断—tasklet—工作队列
软中断/tasklet/工作队列______整理软中断、tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的“下半部”(bottom half)演变而来。
下半部的机制实际上包括五种,但2.6版本的内核中,下半部和任务队列的函数都消失了,只剩下了前三者。
本文重点在于介绍这三者之间的关系。
(函数细节将不会在本文中出现,可以参考文献,点这里)(1)上半部和下半部的区别上半部指的是中断处理程序,下半部则指的是一些虽然与中断有相关性但是可以延后执行的任务。
举个例子:在网络传输中,网卡接收到数据包这个事件不一定需要马上被处理,适合用下半部去实现;但是用户敲击键盘这样的事件就必须马上被响应,应该用中断实现。
两者的主要区别在于:中断不能被相同类型的中断打断,而下半部依然可以被中断打断;中断对于时间非常敏感,而下半部基本上都是一些可以延迟的工作。
由于二者的这种区别,所以对于一个工作是放在上半部还是放在下半部去执行,可以参考下面四条:a)如果一个任务对时间非常敏感,将其放在中断处理程序中执行。
b)如果一个任务和硬件相关,将其放在中断处理程序中执行。
c)如果一个任务要保证不被其他中断(特别是相同的中断)打断,将其放在中断处理程序中执行。
d)其他所有任务,考虑放在下半部去执行。
(2)为什么要使用软中断?软中断作为下半部机制的代表,是随着SMP(share memory processor)的出现应运而生的,它也是tasklet实现的基础(tasklet实际上只是在软中断的基础上添加了一定的机制)。
软中断一般是“可延迟函数”的总称,有时候也包括了tasklet(请读者在遇到的时候根据上下文推断是否包含tasklet)。
它的出现就是因为要满足上面所提出的上半部和下半部的区别,使得对时间不敏感的任务延后执行,而且可以在多个CPU上并行执行,使得总的系统效率可以更高。
它的特性包括:a)产生后并不是马上可以执行,必须要等待内核的调度才能执行。
softirq(软中断)下半部中tasklet与workqueue的区别
softirq(软中断)下半部中tasklet与workqueue的区别一、中断处理的tasklet(小任务)机制中断服务程序一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化。
但是,中断是一个随机事件,它随时会到来,如果关中断的时间太长,CPU就不能及时响应其他的中断请求,从而造成中断的丢失。
因此,Linux内核的目标就是尽可能快的处理完中断请求,尽其所能把更多的处理向后推迟。
例如,假设一个数据块已经达到了网线,当中断控制器接受到这个中断请求信号时,Linux内核只是简单地标志数据到来了,然后让处理器恢复到它以前运行的状态,其余的处理稍后再进行(如把数据移入一个缓冲区,接受数据的进程就可以在缓冲区找到数据)。
因此,内核把中断处理分为两部分:上半部(tophalf)和下半部(bottomhalf),上半部(就是中断服务程序)内核立即执行,而下半部(就是一些内核函数)留着稍后处理,首先,一个快速的“上半部”来处理硬件发出的请求,它必须在一个新的中断产生之前终止。
通常,除了在设备和一些内存缓冲区(如果你的设备用到了DMA,就不止这些)之间移动或传送数据,确定硬件是否处于健全的状态之外,这一部分做的工作很少。
下半部运行时是允许中断请求的,而上半部运行时是关中断的,这是二者之间的主要区别。
但是,内核到底什时候执行下半部,以何种方式组织下半部?这就是我们要讨论的下半部实现机制,这种机制在内核的演变过程中不断得到改进,在以前的内核中,这个机制叫做bottomhalf(简称bh),在2.4以后的版本中有了新的发展和改进,改进的目标使下半部可以在多处理机上并行执行,并有助于驱动程序的开发者进行驱动程序的开发。
下面主要介绍常用的小任务(Tasklet)机制及2.6内核中的工作队列机制。
小任务机制这里的小任务是指对要推迟执行的函数进行组织的一种机制。
其数据结构为tasklet_struct,每个结构代表一个独立的小任务,其定义如下:[cpp] view plain copy<spanstyle="font-weight: normal;">struct tasklet_struct { struct tasklet_struct *next; /*指向链表中的下一个结构*/ unsignedlong state; /* 小任务的状态*/ atomic_tcount; /* 引用计数器*/ void(*func) (unsigned long); /* 要调用的函数*/ unsignedlong data; /* 传递给函数的参数*/ };</span> 结构中的func域就是下半部中要推迟执行的函数,data是它唯一的参数。
linux中断处理上半部下半部实例
linux中断处理上半部下半部实例Linux中断处理是操作系统中非常重要的一个功能,它负责处理硬件设备的中断请求。
中断处理过程可以分为上半部和下半部两个阶段。
本文将通过一个实例来详细介绍Linux中断处理的上半部和下半部。
让我们来了解一下什么是中断。
在计算机系统中,中断是指硬件设备向CPU发送信号,通知CPU需要进行处理的事件。
当CPU接收到中断信号时,会暂停当前正在执行的任务,并转而处理中断请求。
这样可以提高系统的响应速度和效率。
在Linux中,中断处理分为上半部和下半部。
上半部是指中断处理程序的第一阶段,它需要尽快地完成一些关键的任务,以确保系统的稳定性。
下半部是指中断处理程序的第二阶段,它可以在上半部完成的基础上进行更复杂、耗时的操作。
下面我们通过一个实例来说明中断处理的上半部和下半部。
假设我们有一个网络设备,它负责接收和发送网络数据包。
当有数据包到达时,设备会发送一个中断请求给CPU,通知CPU有数据包需要处理。
在中断处理的上半部,首先需要读取网络设备的状态寄存器,以确定中断的原因。
然后,根据中断的原因,执行相应的处理操作。
例如,如果是接收到数据包的中断,那么上半部需要将数据包从设备的接收缓冲区中读取出来,并且进行一些必要的校验和处理。
上半部的任务还包括更新设备的状态、清除中断标志等。
这些任务需要尽快完成,以确保系统的稳定性和实时性。
因此,在上半部的处理过程中,需要尽量避免长时间的延迟和阻塞操作。
当上半部的任务完成后,中断处理程序就会进入下半部。
下半部的任务可以是一些比较耗时的操作,例如将数据包交给上层协议栈进行处理、更新网络设备的缓冲区等。
由于下半部的任务可能会比较耗时,所以通常会通过软中断或工作队列的方式来延迟执行。
在Linux中,可以使用软中断来实现下半部的延迟执行。
软中断是一种由内核触发的中断,它可以在合适的时机执行下半部的任务。
通过软中断,可以将下半部的任务延迟到合适的时间点执行,以避免对系统的影响。
浅析Linux内核中的Bottom Half机制
1然后 返 回 , 下 的工作 交 . 剩
给相 应的 B H来处 理 。当 内核每次 执行 完 d —R ( oIQ )
中的中断服务程序之后 , 或者 每次系统调用 结束之时 ,
o 函数 d b t m h l )得 到 触 发 ,它将 执 行相 应 的 o ot af(
_ _
b at e和 b _ s h cv i h ma 。 的 H
格。 因此它通 常是在 C U 开 中断 的条件下执 行的 。 P 但
是 .iu Ln x早期 实现 的 B t m H l机 制 B 函数接 口 ot a o f H
B 函数 接 口实 现 简 单 , 有 严 重 的 缺 陷 , 重 要 H 但 最
的两 个就是 :严 格 串行 化不 能利 用 S MP:只有 3 2个
较为严格 . 须在 中断请 求发生 后立 即或至 少在一 定 必
素 , 以确定 是否开 启/ 用 关闭 B 函数 。当执行 某硬 件 H
中断 服务 程 序 时 。 如果 需 要 执 行一 个 B 函数 , 件 H 硬 中断 服 务 的 T pHa o l 需 通 过 函数 mak b ( 将 f只 r— h )
用, 为此 , 早期 的 20内核后 续版 本义 对 B . H进 行 了扩 二 展, 引入 了 T s u u , 是一个 双 向队列链 表 。 akQ e e 它
一
一
第
队列的每个元 素都 有一 个 函数指 针及 其参 数 , 它 九
b at e h c v 中的相应 位设成 i
_
的 时间 限制 内完成 .为 了保 证这 种 处理 能原 子地 完 成 ,o a T pH l 常是在 C U 关 中断的 条件 下执 行的 。 f通 P
linux中断上半部和下半部的理解
linux中断上半部和下半部的理解Linux中断是操作系统中的一种机制,用于处理系统硬件设备的事件和异常。
在Linux内核中,中断处理程序分为上半部和下半部,这两部分共同完成中断处理的工作。
上半部是中断处理程序的第一部分,主要负责快速响应中断事件,并进行一些必要的处理。
当硬件设备触发中断信号时,CPU会立即停止当前执行的任务,转而执行与中断相关的处理程序。
上半部的代码必须尽可能地短小和高效,以确保能够在最短的时间内完成对中断事件的响应。
在上半部中,通常只会进行一些必要的初始化工作,如保存寄存器状态、禁止其他中断的触发等。
由于上半部需要尽快完成,因此在这个阶段不适合进行复杂的计算或与其他模块进行交互。
下半部是中断处理程序的第二部分,负责完成上半部无法完成的工作。
由于上半部需要尽快完成,因此有些复杂的任务可能无法在上半部中完成。
这时,下半部就起到了补充的作用。
下半部可以在稍后的时间继续执行,以完成一些需要较长时间的操作,如磁盘IO操作、网络通信等。
在下半部中,可以调用其他模块的函数、进行复杂的计算等。
下半部可以分为软中断、任务队列和工作队列等几种形式,用于执行不同类型的任务。
上半部和下半部的分离有助于提高系统的响应速度和并发能力。
上半部的快速响应保证了对中断事件的及时处理,而下半部的延迟执行则可以避免在中断处理期间对系统造成过大的负担。
此外,上半部和下半部的分离还可以提高系统的可扩展性和可维护性。
上半部和下半部可以分别进行优化和调试,便于系统的开发和维护。
在Linux内核中,中断处理程序的编写是一个复杂而关键的任务。
合理的分离上半部和下半部,并将不同类型的任务分配给不同的下半部机制,可以有效提高中断处理的效率和可靠性。
同时,在编写中断处理程序时,还需要考虑各种特殊情况和异常处理,以保证系统的稳定性和可靠性。
Linux中断的上半部和下半部是中断处理程序的两个重要组成部分。
上半部负责快速响应中断事件,并进行一些必要的初始化工作;下半部则负责完成上半部无法完成的复杂任务。
中断处理程序下半部(软中断、tasklet、工作队列)
中断处理程序下半部1.下半部综述1.1.使用下半部的目的linux将中断处理程序分为上半部和下半部,目的是尽量减少上半部需要完成的工作,因为在上半部执行的时候,当前的中断线在所有处理器上都会被屏蔽。
而且,如果一个处理程序是IRQF_DISABLED类型,它执行的时候会禁止所有本地中断。
而缩短中断被屏蔽的时间对系统的响应能力和性能都至关重要。
因此需要把一些工作放到下半部去做。
不仅是Linux,许多操作系统也把处理硬件中断的过程分为两个部分。
上半部分简单快速,执行的时候禁止一些或全部中断。
下半部分稍后执行,而且执行期间可以响应所有的中断。
这种设计可使系统处于中断屏蔽状态的时间尽可能的短,以此来提高系统的响应能力。
1.2.Linux中的下半部发展和上半部只能通过中断处理程序实现不同,下半部可以通过多种机制实现。
最早的Linux只提供“bottom half”这种机制用于实现下半部。
它提供了一个静态创建、由32个bottom halves组成的链表。
上半部通过一个32位整数中的一个位来标识出哪个bottom half可以执行。
每个BH都在全局范围内进行同步。
即使分属于不同的处理器,也不允许任何两个bottom half同时执行。
不久,内核开发者们就引入了任务队列机制来实现工作的推后执行,并用它来代替BH 机制。
内核为此定义了一组队列,其中每个队列都包含一个由等待调用的函数组成链表。
根据其所处队列的位置,这些函数会在某个时刻执行。
驱动程序可以把他们自己的下半部注册到合适的队列上去。
在2.3这个开发版中,引入了软中断和tasklet。
软中断是一组静态定义的下半部接口,有32个,可以在所有处理器上同时执行——即使两个类型相同也可以。
两个不同类型的tasklet可以在不同的处理器上同时执行,但类型相同的tasklet不能同时执行。
tasklet其实是一种在性能和易用性之间寻求平衡的产物。
对于大部分下半部处理来说,用tasklet就足够了,像网络这样对性能要求非常高的情况下才需要使用软中断。
Linux的中断和系统调用esp、eip等寄存器
Linux的中断和系统调⽤esp、eip等寄存器⼀共三篇中断⼀般分为三类:1、由计算机硬件异常或故障引起的中断,称为内部异常中断;2、由程序中执⾏了引起中断的指令⽽造成的中断,称为软中断(这也是和我们将要说明的系统调⽤相关的中断);3、由外部设备请求引起的中断,称为外部中断。
简单来说,对中断的理解就是对⼀些特殊事情的处理。
当发⽣软件中断时,其他所有的中断都可能发⽣并被处理;但当发⽣磁盘中断时,就只有时钟中断和机器错误中断能被处理了。
⽤户态和核⼼态之间的区别是什么呢?(以下区别摘⾄《UNIX操作系统设计》)1、⽤户态的进程能存取它们⾃⼰的指令和数据,但不能存取内核指令和数据(或其他进程的指令和数据)。
然⽽,核⼼态下的进程能够存取内核和⽤户地址2、某些机器指令是特权指令,在⽤户态下执⾏特权指令会引起错误对此要理解的⼀个是,在系统中内核并不是作为⼀个与⽤户进程平⾏的估计的进程的集合,内核是为⽤户进程运⾏的。
内核⾃⼰的栈这在最上层的1G的地址空间内,这是只能由内核访问的部分。
⽤户态:Ring3运⾏于⽤户态的代码则要受到处理器的诸多检查,它们只能访问映射其地址空间的页表项中规定的在⽤户态下可访问页⾯的虚拟地址,且只能对任务状态段(TSS)中I/O许可位图(I/O Permission Bitmap)中规定的可访问端⼝进⾏直接访问。
内核态:Ring0在处理器的存储保护中,核⼼态,或者特权态(与之相对应的是⽤户态),是操作系统内核所运⾏的模式。
运⾏在该模式的代码,可以⽆限制地对系统存储、外部设备进⾏访问。
⼆、什么情况下会发⽣从⽤户态向内核态切换。
这⾥细分为3种情况。
1、发⽣系统调⽤时这是处于⽤户态的进程主动请求切换到内核态的⼀种⽅式。
⽤户态的进程通过系统调⽤申请使⽤操作系统提供的系统调⽤服务例程来处理任务。
⽽系统调⽤的机制,其核⼼仍是使⽤了操作系统为⽤户特别开发的⼀个中断机制来实现的,即软中断2、产⽣异常时当CPU执⾏运⾏在⽤户态下的程序时,发⽣了某些事先不可知的异常,这时会触发由当前运⾏的进程切换到处理此异常的内核相关的程序中,也就是转到了内核态,如缺页异常。
linux_外部中断处理_底半处理
LINUX外部中断处理(2)
数据结构Irq_desc[]:
/*irq.h(arch/i386/kernel)38行*/
irq_desc_t irq_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}
程序
把bh_base[0]赋给bh
LINUX外部中断处理(2)
run_bottom_halves(void) :
do { if (active & 1) (*bh)(); bh++; active >>= 1;
} while (active); }
active的最低位与1相与,如 果为1,说明相应程序安装
并激活
bh地址加1,bh_mask与 bh_active相与位也右移一位
LINUX外部中断处理(2)
do_IRQ( )执行结束后,返回到ret_from_intr处,进 行一些善后处理,结束中断。
在ret_from_intr处,检查了被中断进程的运行模式: (1)若被中断进程运行在核心态,则跳转到restore_all 程序段,则执行宏RESTORE_ALL,以恢复内核堆栈到中 断前的状态: (2)若被中断进程运行在用户态,则看当前进程是否 需要调度,如果需要调度,则运行调度函数;如果不 需要,则看是否有待处理的信号,若有则先处理信号, 最后再恢复各寄存器的值。
LINUX外部中断处理(2)
do_8259A_IRQ( ) handle_IRQ_event( )
linux内核中断处理流程
Linux内核中断处理流程一、中断概述在计算机系统中,中断是一种重要的机制,它允许处理器暂停当前的程序执行,转而处理更为紧急的事件。
Linux内核作为操作系统的核心,负责管理和处理系统中的各种中断。
中断可以分为外中断(硬件中断)和内中断(软件中断或陷阱),它们在Linux内核中有不同的处理流程。
二、中断处理流程1. 中断请求(IRQ)的接收当中断控制器接收到一个外部设备的中断请求时,它会根据优先级等信息决定是否向CPU发送中断信号。
如果决定发送,CPU会暂停当前的执行流程,开始中断处理。
2. 中断向量的确定每个中断都有一个唯一的中断向量与之对应。
中断向量是中断处理程序的入口点。
在x86架构中,中断向量表(Interrupt Descriptor Table,IDT)存储了系统中所有中断处理程序的地址信息。
CPU根据中断向量从IDT中找到对应的中断处理程序入口。
3. 中断处理程序的执行一旦确定了中断处理程序的入口点,CPU会跳转到该程序并执行。
中断处理程序通常被称为中断服务例程(Interrupt Service Routine,ISR)。
ISR负责处理中断事件,如读取设备数据、更新系统状态等。
4. 中断上下文的保存与恢复在执行ISR之前,CPU需要保存当前执行上下文(包括寄存器状态、程序计数器等),以便在中断处理完成后能够恢复到原来的执行状态。
同样,当中断处理完成时,CPU需要恢复被中断程序的执行上下文。
5. 嵌套中断的处理在某些情况下,一个中断处理程序可能会被另一个更高优先级的中断打断。
这种情况称为嵌套中断。
Linux内核通过中断优先级管理和中断屏蔽等技术来处理嵌套中断,确保系统的稳定性和实时性。
6. 中断结束与返回当中断处理程序执行完毕时,它会通过一条特殊的指令(如iret在x86架构中)来通知CPU中断处理已完成。
CPU随后会恢复被中断程序的执行上下文,并继续执行被中断的程序。
三、软件中断(软中断)和任务调度除了硬件中断外,Linux内核还支持软件中断(Softirqs)和任务调度(Tasklets)机制。
三种中断下半部的实现
软中断,tasklet和工作队列为了让中断处理运行的快,同时要完成相应的全部工作。
根据具体的内容将中断分为两个部分:上半部分(中断处理程序)和下半部分(推后处理程序)。
上半部分需要立即执行,并且有严格的时间限制,这些工作是在所有中断被禁止的情况下完成的,剩余部分工作推迟到下半部分。
下半部分的任务就是执行与中断处理密切相关但中断处理程序本身不执行的工作。
在Linux2.6的内核中存在三种不同形式的下半部实现机制:软中断,tasklet和工作队列。
下面将比较三种机制的差别与联系。
软中断:1、软中断是在编译期间静态分配的。
2、最多可以有32个软中断。
3、软中断不会抢占另外一个软中断,唯一可以抢占软中断的是中断处理程序。
4、可以并发运行在多个CPU上(即使同一类型的也可以)。
所以软中断必须设计为可重入的函数(允许多个CPU同时操作),因此也需要使用自旋锁来保护其数据结构。
5、目前只有两个子系直接使用软中断:网络和SCSI。
6、执行时间有:从硬件中断代码返回时、在ksoftirqd内核线程中和某些显示检查并执行软中断的代码中。
tasklet:1、tasklet是使用两类软中断实现的:HI_SOFTIRQ和TASKLET_SOFTIRQ。
2、可以动态增加减少,没有数量限制。
3、同一类tasklet不能并发执行。
4、不同类型可以并发执行。
5、大部分情况使用tasklet。
工作队列:1、由内核线程去执行,换句话说总在进程上下文执行。
2、可以睡眠,阻塞。
软中断的处理是在内核态,并且是在中断上下文中,这个时候不会发生进程切换。
linux中断机制浅析
linux中断机制浅析广义上的中断可以分为外部中断和内部中断(异常)1.中断是由外部事件引起的,一般分为可屏蔽的中断与非可屏蔽的中断,所谓可屏蔽就是可以通过设置CPU的IF标志位进行屏蔽,而非可屏蔽的是一些非常紧急的事件,往往IF对其不起作用。
2.异常是由于内部事件造成的,比如说缺页异常,系统调用等异常的产生1,监视IRQ线,对引发信号检查(编号小者优先)2,如果一个引发信号出现在IRQ线上a,把此信号转换成对应的中断向量b,把这个向量存放在中断控制器的一个I/O端口,从而允许CPU 通过数据总线读这个向量c,把引发信号发送到处理器的INTR引脚,即产生一个中断d,等待,直到CPU应答这个信号;收到应答后,清INTR引脚3,返回到第1步核心其实中断最核心的东西在于中断描述符表(中断向量表)IDT,他里面记录了中断号与中断处理程序之间的对应关系(确切的说并不是与真正的中断处理程序对应,只是把中断向量号取反压入堆栈,然后跳转到common_interrupt,交给这个函数继续执行)。
)。
表中的每一项称之为中断描述符为64位,linux中IDT表项共计256项,0~31内部中断,128系统调用中断,其他的可以自由使用。
CPU的idtr寄存器指向IDT表的物理基地址,lidt指令IDT初始化在系统进入保护模式之前,中断向量表idt_table中的中断处理函数都是ignore_int,在start_kernel函数中需要重新设置itd_table,这个工作由tarp_init和init_IRQ完成。
其中trap_init主要用来完成固定的映射(异常),而Init_IRQ除了填充中断向量表(外部中断)之外还要进行中断控制器的初始化。
Init_IRQLINUX经常采用面向对象的思想,抽象出来,对于硬件存在很多种中断控制器,Linux将其抽象为irq_chip。
同样由于同一个外部中断号可能被多个外部设备共享,而每个不同的外部设备都可以动态地注册和撤销自己的中断处理程序,所以定义了Irq_desc结构,每一个外部中断(因为在256个中断中,32被保留内部使用,所以共有224个需要irq_desc)需要这样一个结构。
Linux内核新旧工作队列机制的剖析和比较共11页word资料
Linux内核新旧工作队列机制的剖析和比较Analysis and Comparison of the New and Old Work Queue in Linux KernelMA Jun-qiang(School of Information Science and Engineering, Xiamen University, Xiamen 361005, China)Abstract: Work Queue is a powerful tool in interrupt-driven programming. But in Linux kernels of 2.6.35 and before, it consumes a lot of kernel resources in that whenever a Work Queue is created,the same number of kernel threads as CPUs are created. The efficiency to processing works in Work Queue is low due to strictly sequential processing. In order to adapt the hardware platforms withlarge-scale multiprocessors and increase the processing efficiency, the Linux kernel of 2.6.36 developed Concurrency Managed Workqueue. With this new mechanism, the kernel creates and destroys the threads according to the processing requirements, and works can be concurrently processed. The new Work Queue is hoped to replace the private thread tools that had been used long time. The paper introduces and analyses this new mechanism in detail,and compares the resource consumes and processing efficiency between the new and old mechanisms by experiments. The results show that the new mechanism of Work Queue greatly reduces consumes ofkernel resources and increases the processing efficiency.当一个中断发生时,并不是相关的各个操作都具有相同的急迫性,把所有的操作都放进中断处理程序本身也不合适。
linux内核分析笔记----中断和中断处理程序
linux内核分析笔记----中断和中断处理程序中断还是中断,我讲了很多次的中断了,今天还是要讲中断,为啥呢?因为在操作系统中,中断是必须要讲的..那么什么叫中断呢,中断还是打断,这样一说你就不明白了。
唉,中断还真是有点像打断。
我们知道linux管理所有的硬件设备,要做的第一件事先是通信。
然后,我们天天在说一句话:处理器的速度跟外围硬件设备的速度往往不在一个数量级上,甚至几个数量级的差别,这时咋办,你总不能让处理器在那里傻等着你硬件做好了告诉我一声吧。
这很容易就和日常生活联系起来了,这样效率太低,不如我处理器做别的事情,你硬件设备准备好了,告诉我一声就得了。
这个告诉,咱们说的轻松,做起来还是挺费劲啊!怎么着,简单一点,轮训(polling)可能就是一种解决方法,缺点是操作系统要做太多的无用功,在那里傻傻的做着不重要而要重复的工作,这里有更好的办法---中断,这个中断不要紧,关键在于从硬件设备的角度上看,已经实现了从被动为主动的历史性突破。
中断的例子我就不说了,这个很显然啊。
分析中断,本质上是一种特殊的电信号,由硬件设备发向处理器,处理器接收到中断后,会马上向操作系统反应此信号的带来,然后就由OS负责处理这些新到来的数据,中断可以随时发生,才不用操心与处理器的时间同步问题。
不同的设备对应的中断不同,他们之间的不同从操作系统级来看,差别就在于一个数字标识-----中断号。
专业一点就叫中断请求(IRQ)线,通常IRQ都是一些数值量。
有些体系结构上,中断好是固定的,有的是动态分配的,这不是问题所在,问题在于特定的中断总是与特定的设备相关联,并且内核要知道这些信息,这才是最关键的,不是么?哈哈.用书上一句话说:讨论中断就不得不提及异常,异常和中断不一样,它在产生时必须要考虑与处理器的时钟同步,实际上,异常也常常称为同步中断,在处理器执行到由于编程失误而导致的错误指令的时候,或者是在执行期间出现特殊情况,必须要靠内核来处理的时候,处理器就会产生一个异常。
Linux中断详解
深入剖析Linux中断机制--中断概述【摘要】本文详解了Linux内核的中断实现机制。
首先介绍了中断的一些基本概念,然后分析了面向对象的Linux中断的组织形式、三种主要数据结构及其之间的关系。
随后介绍了Linux处理异常和中断的基本流程,在此基础上分析了中断处理的详细流程,包括保存现场、中断处理、中断退出时的软中断执行及中断返回时的进程切换等问题。
最后介绍了中断相关的API,包括中断注册和释放、中断关闭和使能、如何编写中断ISR、共享中断、中断上下文中断状态等。
【关键字】中断,异常,hw_interrupt_type,irq_desc_t,irqaction,asm_do_IRQ,软中断,进程切换,中断注册释放request_irq,free_irq,共享中断,可重入,中断上下文1 中断概述1.1 为什么需要中断?处理器的速度跟外围硬件设备的速度往往不在一个数量级上,因此,如果内核采取让处理器向硬件发出一个请求,然后专门等待回应的办法,显然差强人意。
既然硬件的响应这么慢,那么内核就应该在此期间处理其他事务,等到硬件真正完成了请求的操作之后,再回过头来对它进行处理。
想要实现这种功能,轮询(polling)可能会是一种解决办法。
可以让内核定期对设备的状态进行查询,然后做出相应的处理。
不过这种方法很可能会让内核做不少无用功,因为无论硬件设备是正在忙碌着完成任务还是已经大功告成,轮询总会周期性地重复执行。
更好的办法是由我们来提供一种机制,让硬件在需要的时候再向内核发出信号(变内核主动为硬件主动)。
这就是中断机制。
1.2 中断的表示形式硬件设备生成中断的时候并不考虑与处理器的时钟同步—换句话说就是中断随时可以产生。
因此,内核随时可能因为新到来的中断而被打断。
从物理学的角度看,中断是一种电信号,由硬件设备生成,并直接送入中断控制器的输入引脚上。
然后再由中断控制器向处理器发送相应的信号。
处理器一经检测到此信号,便中断自己的当前工作转而处理中断。
Linux中关于中断和fork的学习笔记
void (*function)(unsigned long);//定时器处理函数 unsigned long data; //作为参数传入定时器处理函数
于函数调用,存放函数参数、函数内部定义的局部变量。
调用fork函数后,当前进程分裂为两个进程,一个是原来的父进程,另一个是刚 创建的子进程。父进程调用fork后返回值是子进程的ID,子进程中返回值是 0,若进 程创建失败,只返回-1。失败原因一般是父进程拥有的子进程个数超过了规定限制 (返回EAGAIN)或者内存不足(返回ENOMEM)。我们可以依据返回值判断进程, 一般情况下fork后父子进程谁先执行是未定的,取决于内核所使用的调度算法。一 般情况下os让所有进程享有同等执行权,除非某些进程优先级高。若有一个孤儿进 程,即父进程先于子进程死去,子进程将会由init进程收养。
给定中断后立即返回。 (4)屏蔽本cpu内的所有中断 void local_irq_save (unsigned flags);//保存中断状态后,禁止中断 void local_irq_disable(void);//关闭中断不保存状态 以local开头说明作用范围在本cpu内。 (5)在include/linux/interrupt.h 中定义了 struct tasklet_struct { struct tasklet_struct *next; unsigned long state; atomic_t count; //原子计数 void (*func)(unsigned long); // 处理函数 unsigned long data; //传入处理函数的参数 }; #define DECLARE_TASKLET(name, func, data) \ struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data } 它定义了一个tasklet_struct结构,并且与func函数关联,func为该tasklet的处理函
中断的下半部和上半部
linux 中断的上半部和下半部2009-12-09 07:27另外,与Linux中断息息相关的一个重要概念是Linux中断分为两个半部:上半部(tophalf)和半部(bottom half)。
上半部的功能是"登记中断",当一个中断发生时,它进行相应地硬件读写后就把中断例程的半部挂到该设备的半部执行队列中去。
因此,上半部执行的速度就会很快,可以服务更多的中断请求。
但是,仅有"登记中断"是远远不够的,因为中断的事件可能很复杂。
因此,Linux引入了一个半部,来完成中断事件的绝大多数使命。
半部和上半部最大的不同是半部是可中断的,而上半部是不可中断的,半部几乎做了中断处理程序所有的事情,而且可以被新的中断打断!半部则相对来说并不是非常紧急的,通常还是比较耗时的,因此由系统自行安排运行时机,不在中断服务上文中执行。
Linux实现半部的机制主要有tasklet和工作队列。
Tasklet基于Linux softirq,其使用相当简单,我们只需要定义tasklet 及其处理函数并将二者关联:void my_tasklet_func(unsigned long); //定义一个处理函数:DECLARE_TASKLET(my_tasklet,my_tasklet_func,data); //定义一个tasklet结构my_tasklet,与my_tasklet_func(data)函数相关联然后,在需要调度tasklet的时候引用一个简单的API就能使系统在适当的时候进行调度运行:tasklet_schedule(&my_tasklet);此外,Linux还提供了另外一些其它的控制tasklet调度与运行的API:DECLARE_TASKLET_DISABLED(name,function,data); //与DECLARE_TASKLET类似,但等待tasklet被使能tasklet_enable(struct tasklet_struct *); //使能tasklettasklet_disble(struct tasklet_struct *); //禁用tasklettasklet_init(struct tasklet_struct *,void(*func)(unsigned long),unsigned long); //类似DECLARE_TASKLET()tasklet_kill(struct tasklet_struct *); // 清除指定tasklet的可调度位,即不允许调度该tasklet我们先来看一个tasklet的运行实例,这个实例没有任何实际意义,仅仅为了演示。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
b l o g . c h i n a u n i x . n e t / u i d 2 0 7 6 8 9 2 8 i d 5 0 7 7 4 0 1 . h t ml
1 5 6 1 6l i n u x
-l i n u x R S 4 8 5
i s p s u b b C h i n a U n i x
lwfbibi
D2002
chunhui_
2 / 7
b l o g . c h i n a u n i x . n e t / u i d 2 0 7 6 8 9 2 8 i d 5 0 7 7 4 0 1 . h t ml
1 5 6 1 6l i n u x
-l i n u x R S 4 8 5
i s p s u b b C h i n a U n i x
考/angle_birds/article/details/8448070
yzj_1988
64492407
紫易幼南
点击(此处)折叠或打开 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 . 9 . 1 0 . 1 1 . 1 2 . 1 3 . 1 4 . D E C L A R E _ W O R K ( s t r u c tw o r k _ s t r u c t,w o r k _ f u n c _ tf u n c ) ; I N I T _ W O R K ( s t r u c tw o r k _ s t r u c t* w o r k ,w o r k _ f u n c _ tf u n c ) ; I N I T _ D E L A Y E D _ W O R K ( s t r u c td e l a y e d _ w o r k* w o r k ,w o r k _ f u n c _ tf u n c ) ; i n ts c h e d u l e _ w o r k ( s t r u c tw o r k _ s t r u c t* w o r k ) ; i n ts c h e d u l e _ d e l a y e d _ w o r k ( s t r u c td e l a y e d _ w o r k* w o r k ,u n s i g n e dl o n gd e l a y ) ; i n ts c h e d u l e _ d e l a y e d _ w o r k _ o n ( s t r u c td e l a y e d _ w o r k* w o r k ,u n s i g n e dl o n gd e l a y ) ; s t r u c tw o r k q u e u e _ s t r u c t* c r e a t e _ w o r k q u e u e ( c o n s tc h a r* n a m e ) ; i n tq u e u e _ w o r k ( s t r u c tw o r k q u e u e _ s t r u c t* w q ,s t r u c tw o r k _ s t r u c t* w o r k ) ; i n tq u e u e _ d e l a y e d _ w o r k ( s t r u c tw o r k q u e u e _ s t r u c t* w q ,s t r u c td e l a y e d _ w o r k* w o r k , u n s i g n e dl o n gd e l a y ) ; v o i df l u s h _ s c h e d u l e d _ w o r k ( v o i d ) ; v o i df l u s h _ w o r k q u e u e ( s t r u c tw o r k q u e u e _ s t r u c t* w q ) ; i n tc a n c e l _ d e l a y e d _ w o r k ( s t r u c td e l a y e d _ w o r k* w o r k ) ; v o i dd e s t r o y _ w o r k q u e u e ( s t r u c tw o r k q u e u e _ s t r u c t* w q ) ;
文章存档 2015年 (4) 2014年 (4) 2012年 (7)
我的朋友
最近访客
liuyingj
yadunhah
headstro
工作队列,任务队列,软中断
工作队列 :Linux kernel中将工作推后执行的一种机制。这种机制和BH或Tasklets不同之处在于工作队 列是把推后的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。工作 队列是2.6内核开始引入的机制,在2.6.20之后,工作队列的数据结构发生了一些变化。可以参
1 5 6 1 6l i n u x
-l i n u x R S 4 8 5
i s p s u b b C h i n a U n i x
Chinaunix首页 | 论坛 | 认证专区 | 博客
登录 | 注册
博文
ispsubb的ChinaUnix博客
After all ,tomorrow is another day !
在LINUX RS485的使用过程中,由于各种原因,最后不得不使用中断底半部机制的方法来进行实现此 功能。先讲两个小故事来描述一下,遇到的问题。也是因为自己对底半部机制理解得不透彻。这些故事的 前提都是在串口中断中,一定条件后去完成某件事情,但时间上不能超过5ms。 故事一,最开始想到的是用workqueue 。印象中workqueue 就是用来做这种事的,并且还记得可以延时 一段时间再来做。
点击(此处)折叠或打开 1 . 2 . 3 . I N I T _ W O R K ( & m y _ w q , ( v o i d( * )( v o i d * ) ) m y _ w q _ f u n c ) ; s c h e d u l e _ w o r k ( & m y _ w q ) ; / / s c h e d u l e _ d e l a y e d _ w o r k ( & m y _ w q , d e l a y ) ;
故事二,工作队列不行后,感觉底半部机制就实现不了,满足不了我们的要求。上网翻了一些资料,觉 得任务队列时效性应该比工作队列更好。就像买药的做广告一样,抱着试一试的态度尝试了一下。
最终这种方法实现了。但过程也是相当曲折。tasklet_schedule时效性可以达到,hi_schedule 更是完 美,感觉会牺牲系统性能。那么过程曲折在哪呢?刚开始以为搞好了,回家睡大觉,等我九点半到家,同 事打电话说不行,出问题了。单个串口没有问题,多个串口同时用的时候,前面打开的串口对应 的rs485 都不能正常使用。GPIO拉高后,就不低。而my_wq_func就是实现GPIO拉低的动作。最后的原因 是my_wq_func被多次调用,而其只响应最后一次。这个地方还得感谢这位老兄, /goodluckwhh/article/details/9003353 。tasklet 是一个特殊的函数, 它在软 中断上下文被调度。它可能被调度运行多次,但是tasklet调度不累积,也就是即使在tasklet被执行之前 请求了多次来执行该tasklet,它也只运行一次。不会有同一个tasklet的多个实例同时运行。但 是tasklet可以与SMP系统上的其他tasklet并行运行。因此, 如果多个tasklet会使用相同的资源, 它们必 须采取某类加锁来避免彼此冲突。除非tasklet重新激活自己,否则每次tasklet激活只会运行一次。最后 的解决方法就是将my_wq_func一个函数可以实现的内容,复制成了四个函数,问题就解决了。 故事讲完了,这时候该来分析分析理论上的底半部机制。前面的曲折,主要是因为自己对底半部机制的 一知半解。这里来着重分析一下任务队列,工作队列的区别,同时也COPY一些别人对软中断的理解,以备 后续查看
情况,我们要求小于5ms。
文章分类 全部博文 (15) translate (0) job and life (0) bootloader (0) android (0) C ASM …… (0) linux (15) arm (0) 未分配的博文 (0) 点击(此处)折叠或打开 1 . 2 . 3 . t a s k l e t _ i n i t ( & m y _ t a s k 0 , m y _ w q _ f u n c , ( u n s i g n e dl o n g )m y _ w q _ a r g ) ; t a s k l e t _ s c h e d u l e ( & m y _ t a s k 0 ) ; t a s k l e t _ h i _ s c h e d u l e ( & m y _ t a s k 0 ) ;
点击(此处)折叠或打开 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 . D E C L A R E _ T A S K L E T ( n a m e ,f u n c ,d a t a ) ; v o i dt a s k l e t _ i n i t ( s t r u c tt a s k l e t _ s t r u c t* t , v o i d( * f u n c ) ( u n s i g n e dl o n g ) ,u n s i g n e dl o n gd a t a ) ; v o i dt a s k l e t _ s c h e d u l e ( s t r u c tt a s k l e t _ s t r u c t* t ) ; v o i dt a s k l e t _ h i _ s c h e d u l e ( s t r u c tt a s k l e t _ s t r u c t* t ) ; v o i dt a s k l e t _ d i s a b l e ( s t r u c tt a s k l e t _ s t r u c t* t ) ; v o i dt a s k l e t _ d i s a b l e _ n o s y n c ( s t r u c tt a s k l e t _ s t r u c t* t ) ; v o i dt a s k l e t _ e n a b l e ( s t r u c tt a s k l e t _ s t r u c t* t ) ; v o i dt a s k l e t _ k i l l ( s t r u c tt a s k l e t _ s t r u c t* t ) ;