《深入理解Linux内核》笔记4:软中断_tasklet_工作队列葡萄的技术博客百度空间
- 格式:pdf
- 大小:195.74 KB
- 文档页数:3
Linux 内核软中断(softirq)执行分析Author: sinisterEmail: sinister@Homepage:Date: 2007-01-11本文对 Linux 内核软中断的执行流程进行了分析,并尽可能的结合当前运行环境详细地写出我的理解,但这并不表明我的理解一定正确。
这本是论坛里的一篇帖子,发出来是为了抛砖引玉,如果您在阅读本文时发现了我的错误,还望得到您的指正。
今天无意中看了眼 2.6 内核的软中断实现,发现和以前我看到的大不相同(以前也是走马观花,不大仔细),可以说改动很大。
连 softirq 的调用点都不一样了,以前是三个调用点,今天搜索了一下源代码,发现在多出了ksoftirqd 后,softirq 在系统中的调用点仅是在 ISR 返回时和使用了local_bh_enable() 函数后被调用了。
网卡部分的显示调用,我觉得应该不算是系统中的调用点。
ksoftirqd 返回去调用 do_softirq() 函数应该也只能算是其中的一个分支,因为其本身从源头上来讲也还是在 ISR 返回时irq_exit() 调用的。
这样一来就和前些日子写的那份笔记(Windows/Linux /Solaris 软中断机制)里介绍的 Linux 内核部分的软中断有出处了,看来以后讨论 Linux kernel 代码一定要以内核版本为前题,要不非乱了不可。
得买本 Linux 方面的书了,每次上来直接看相关代码也不是回事,时间也不允许。
//// do_IRQ 函数执行完硬件 ISR 后退出时调用此函数。
//void irq_exit(void){account_system_vtime(current);trace_hardirq_exit();sub_preempt_count(IRQ_EXIT_OFFSET);//// 判断当前是否有硬件中断嵌套,并且是否有软中断在// pending 状态,注意:这里只有两个条件同时满足// 时,才有可能调用 do_softirq() 进入软中断。
tasklet和工作队列tasklet和工作队列分类:LINUX设备驱动程序第三版2013-01-22 16:00 418人阅读评论(0) 收藏举报tasklet和定时器相关的另一个内核设施是taskled(小任务)机制。
中断管理中大量使用了这种机制。
task在很多方面类似内核定时器:它们始终在中断期间运行,始终会在调度它们的同一CPU上运行,而且都接收一个unsigned long参数,tasklet也会在“软件中断”上下文以原子模式执行。
和内核同时器不同的是,我们不能要求tasklet在某个给定时间执行。
软件中断是指打硬件中断的同时执行某些异步任务的一种内核机制。
tasklet的数据结构如下,使用前必须初始化,调用特定的函数或使用特定的宏来声明该结构,可以完成tasklet的初始化:#includestruct tasklet_struct{/*.....*/void (*func)(unsigned long);unsigned long data;};void tasklet_init(struct tasklet_struct *t),void (*func)(unsigned long), unsigned long data);DECLARE_TASKLET(name, func, data);DECLARE_TASKLET_DISABLED(name, func, data);tasklet为我们提供了许多有意思的特性:一个tasklet可以稍后被禁止或者重新启用;只有启用的次数和禁止的次数相同时,tasklet才会被执行和定时器类似,tasklet可以注册自身tasklet可被调度以在通常的优先级或者高优先级执行。
高优先级的tasklet总会首先执行。
如果系统负荷不重,则tasklet会立即得到执行,但始终不会晚于下一个定时器滴答。
一个tasklet可以和其他tasklet并发,但对自身来讲是严格串行处理的,也就是说,同一tasklet永远不会在多个处理器上同时运行。
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引入了一个下半部,来完成中断事件的绝大多数使命。
下半部和上半部最大的不同是下半部是可中断的,而上半部是不可中断的,下半部几乎做了中断处理程序所有的事情,而且可以被新的中断打断!下半部则相对来说并不是非常紧急的,通常还是比较耗时的,因此由系统自行安排运行时机,不在中断服务上下文中执行。
一、Linux内核中断处理简介1.1、裸机中断1.2 linux中断1、先知道你要使用的中断对应的中断号。
2、先申请request_irq,此函数会激活中断。
3、如果不用中断了,那就释放掉,使用free_irq。
4、中断处理函数irqreturn_t (*irq_handler_t) (int, void *)。
5、使能和禁止中断,1.3 上半部和下半部中断一定要处理的越快越好,1、软中断static struct softirq_action softirq_vec[NR_SOFTIRQS] 10个要使用软中断,要先注册,使用函数open_softir。
注册以后使用raise_softirq触发。
软中断我们不要去用!!软中断我们不要去用!!2、tasklet也需要用到上半部,只是上半部的中断处理函数重点是调用tasklet_schedule。
1、定义一个tasklet函数。
2、初始化、重点是设置对应的处理函数3、工作队列1.4 设备树中断节点信息1、#interrupt-cells指定interrupt的cells数量,也就是属性interrupts。
intc: interrupt-controller@00a01000 {compatible = "arm,cortex-a7-gic";#interrupt-cells = <3>;interrupt-controller;reg = <0x00a01000 0x1000>,<0x00a02000 0x100>;};gpio5: gpio@020ac000 {compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";reg = <0x020ac000 0x4000>;interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,<GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;gpio-controller;#gpio-cells = <2>;interrupt-controller;#interrupt-cells = <2>;};fxls8471@1e {compatible = "fsl,fxls8471";reg = <0x1e>;position = <0>;interrupt-parent = <&gpio5>;interrupts = <0 8>;};interrupt-parent指定父中断。
Softirq_Tasklet_Workqueue区别联系
软中断(softirq)是内核使用的一种推后执行任务的一种机制,由于一些中断处理必须要在短期内完成,所以内核不得不把一些相对不重要的工作推后执行,软中断就是专门用来执行这种后退的工作。
它在某种程度上有点像硬件中断,来得“随时随地”,而且不在进程上下文之中。
千万不要把它和“软件中断(software interrupts)”这个概念混了,后者是因为在编程中使用了中断指令(比如:int 0×80)而产生一个硬件上实际存在的中断信号,而前者更本就不和硬件扯关系。
小任务(tasklet)是在软中断的基础上实现的一种后推执行方式。
软中断是在编译时就已经确定好的,而小任务则可以在运行时分配和初始化;软中断可以在不同的CPU上同时执行,而同一类型的tasklet 只能在调度它们的同一CPU上运行,因此软中断函数必须是可重入的,而小任务的函数则没有这个必要。
工作队列(work queue)是另一种后推方式,但它和小任务有着很大的区别,小任务是在中断上下文中执行的,而工作队列是在进程上下文中执行的,所以工作队列是可以休眠的,也就不一定是原子的。
执行工作队列的线程是ksoftirqd/n(n是cpu的编号,在UP是ksoftirqd/0),这是一个内核线程,因此也不能访问用户内存。
下半部(bottom half)是后推执行任务的一个统称,它主要是完成上半部未完成的一些工作。
一般来说,在处理中断时,在中断处理例程(上半部)中做的工作越少越好,其余一些相对不那么迫切的工作可以后推给下半部来完成,当然了,下半部可以是小任务,也可以是工作队列。
linux内核分析笔记----linux内核简介操作系统的概念我就不细说了。
对于提供保护机制的现代操作来说,内核独立于普通应用程序,它一般处于系统态,拥有受保护的内存空间和访问硬件设备的所有权限,这种系统态和被保护起来的内存空间,统称为内核空间。
相对的,应用程序在用户空间执行,它们只能看到允许它们使用的部分系统资源,并且不能使用某些特定的系统功能,不能直接访问硬件,还有其他一些使用限制。
当内核运行的时候,系统才进入内核空间。
应用程序通过系统调用和内核通信来运行。
应用程序通常调用库函数----比如C库函数-----再由库函数通过系统调用界面让内核代其完成各种不同任务。
在这种情况下,应用程序被称为通过系统调用在内核空间运行,而内核被称为运行于进程上下文中。
内核还要负责管理系统的硬件设备。
当硬件设备想要和系统通信的时候,它首先要发出一个异步的中断信号去打断内核正在执行的工作,中断通常对应着一个中断号,内核通过这个中断号查讯相应的中断服务程序,并调用这个程序响应和处理中断。
为了保证同步,内核可以停用中止---既可以停止所有的中断也可以有选择的停止某个中断号对应的中断。
许多操作系统的中断服务程序都不在进程上下文中执行,它们在一个与所有进程都无关的,专门的中断上下文中运行。
Linux内核和Unix内核的比较这里就不说了,网上一大把,是不。
Linux内核版本(如2.6.32),第一个数字是主版本号;第二个数字是从版本号,偶数代表着稳定版,奇数代表着开发版;第三个是修订版本号;头两个数字在一起描述了内核系列。
内核源代码通常安装在/usr/src/linux子目录中,最好别直接用这里的代码进行开发,因为你的C库通常是根据这个子目录下代码对应的版本进行链接的。
相对于用户空间内应用程序的开发,内核开发有很多不同于用户空间开发的特点。
如下:1.内核编程时不能访问C库.2.内核编程时必须使用GUN C.3.内核编程时缺乏像用户空间那样的内存保护机制.4.内核编程时浮点数很难使用.5.内核只有一个很小的定长堆栈.和并发。
Tasklets一、tasklet使用Tasklet的使用比较简单,只需要定义tasklet及其处理函数并将两者关联例子:Void my_tasklet_func(unsigned long)DECLARE_TASKLET(my_tasklet.my_tasklet_func,data)代码DECLARE_TASKLET实现了定义名称为my_tasklet的tasklet并将其与my_tasklet_func这个函数绑定,而传入这个函数的参数为data。
需要调度tasklet的时候引用一个tasklet_schedule()函数就能使系统在适当的时候进行调度,如下所示Tasklet_schedule(&my_tasklet)下面给出驱动模板Void xxx_do_tasklet(unsigned long);DECLARE_TASKLET(xxx_tasklet,xxx_do_tasklet,0);Void xxx_do_tasklet(unsigned long){……}Irqreturn_t xxx_interrupt(int irq,void *dev_id,struct pt_regs *regs){……Tasklet_schedule(&xxx_tasklet);……}Int _init xxx_init(void){……Result=request_irq(xxx_irq,xxx_interrupt,SA_INTERRUPT,”xxx”,NULL)……}Void _exit xxx_exit(void){……Free_irq(xxx_irq,xxx_irq_interrupt);……}二、tasklet函数详解它对于中断处理特别有用:硬件中断必须尽快处理, 但大部分的数据管理可以延后到以后安全的时间执行。
tasklet 以一个数据结构形式存在,使用前必须被初始化。
初始化能够通过调用一个特定函数或者通过使用某些宏定义声明结构:struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }void tasklet_disable(struct tasklet_struct *t);/*函数暂时禁止给定的tasklet被tasklet_schedule 调度,直到这个tasklet 被再次被enable;若这个tasklet 当前在运行, 这个函数忙等待直到这个tasklet退出*/ void tasklet_disable_nosync(struct tasklet_struct *t);/*和tasklet_disable类似,但是tasklet可能仍然运行在另一个CPU */void tasklet_enable(struct tasklet_struct *t);/*使能一个之前被disable的tasklet;若这个tasklet 已经被调度, 它会很快运行。
linux中断理解
Linux中断是一种硬件机制,它允许外部设备向CPU发出请求,以便在设备完成某个任务后立即通知CPU。
中断是一个事件,可以是硬件故障、IO操作、定时器事件等。
当一个中断事件发生时,CPU会暂停当前执行的任务,保存当前状态,然后跳转到中断处理程序。
中断处理程序会根据中断类型执行相应的操作,并返回执行中断前的状态。
在Linux系统中,中断的处理是由内核完成的。
内核中包含了大量的中断处理程序,每个中断事件都会触发相应的中断处理程序。
理解Linux中断对于系统管理员和开发人员来说是至关重要的,因为它们是处理硬件和软件事件的重要机制。
在Linux中,中断可以被用于各种目的,如网络传输、磁盘IO、定时器、键盘和鼠标输入等。
了解Linux中断的工作原理和处理方式对于优化系统性能、排查故障和开发驱动程序非常有帮助。
在实践中,了解中断的使用和处理方式也有助于提高系统的可用性和稳定性。
总之,Linux中断是一种重要的硬件机制,可以用于处理各种事件。
理解中断的原理和处理方式对于系统管理员和开发人员来说是非常重要的。
通过深入了解Linux中断,可以优化系统性能、排查故障和开发驱动程序,提高系统的可用性和稳定性。
- 1 -。
softirq(软中断)下半部中tasklet与workqueue的区别一、中断处理的tasklet(小任务)机制中断服务程序一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化。
但是,中断是一个随机事件,它随时会到来,如果关中断的时间太长,CPU就不能及时响应其他的中断请求,从而造成中断的丢失。
因此,Linux内核的目标就是尽可能快的处理完中断请求,尽其所能把更多的处理向后推迟。
例如,假设一个数据块已经达到了网线,当中断控制器接受到这个中断请求信号时,Linux内核只是简单地标志数据到来了,然后让处理器恢复到它以前运行的状态,其余的处理稍后再进行(如把数据移入一个缓冲区,接受数据的进程就可以在缓冲区找到数据)。
因此,内核把中断处理分为两部分:上半部(tophalf)和下半部(bottomhalf),上半部(就是中断服务程序)内核立即执行,而下半部(就是一些内核函数)留着稍后处理,首先,一个快速的“上半部”来处理硬件发出的请求,它必须在一个新的中断产生之前终止。
通常,除了在设备和一些内存缓冲区(如果你的设备用到了DMA,就不止这些)之间移动或传送数据,确定硬件是否处于健全的状态之外,这一部分做的工作很少。
下半部运行时是允许中断请求的,而上半部运行时是关中断的,这是二者之间的主要区别。
但是,内核到底什时候执行下半部,以何种方式组织下半部?这就是我们要讨论的下半部实现机制,这种机制在内核的演变过程中不断得到改进,在以前的内核中,这个机制叫做bottomhalf(简称bh),在2.4以后的版本中有了新的发展和改进,改进的目标使下半部可以在多处理机上并行执行,并有助于驱动程序的开发者进行驱动程序的开发。
下面主要介绍常用的小任务(Tasklet)机制及2.6内核中的工作队列机制。
小任务机制这里的小任务是指对要推迟执行的函数进行组织的一种机制。
其数据结构为tasklet_struct,每个结构代表一个独立的小任务,其定义如下:[cpp] view plain copy1.<span style="font-weight: normal;">struct tasklet_struct {2.struct tasklet_struct *next; /*指向链表中的下一个结构*/3.unsignedlong state; /* 小任务的状态*/4.atomic_tcount; /* 引用计数器*/5.void(*func) (unsigned long); /* 要调用的函数*/6.unsignedlong data; /* 传递给函数的参数*/7.};</span>结构中的func域就是下半部中要推迟执行的函数,data是它唯一的参数。
软中断/tasklet/工作队列______整理软中断、tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的“下半部”(bottom half)演变而来。
下半部的机制实际上包括五种,但2.6版本的内核中,下半部和任务队列的函数都消失了,只剩下了前三者。
本文重点在于介绍这三者之间的关系。
(函数细节将不会在本文中出现,可以参考文献,点这里)(1)上半部和下半部的区别上半部指的是中断处理程序,下半部则指的是一些虽然与中断有相关性但是可以延后执行的任务。
举个例子:在网络传输中,网卡接收到数据包这个事件不一定需要马上被处理,适合用下半部去实现;但是用户敲击键盘这样的事件就必须马上被响应,应该用中断实现。
两者的主要区别在于:中断不能被相同类型的中断打断,而下半部依然可以被中断打断;中断对于时间非常敏感,而下半部基本上都是一些可以延迟的工作。
由于二者的这种区别,所以对于一个工作是放在上半部还是放在下半部去执行,可以参考下面四条:a)如果一个任务对时间非常敏感,将其放在中断处理程序中执行。
b)如果一个任务和硬件相关,将其放在中断处理程序中执行。
c)如果一个任务要保证不被其他中断(特别是相同的中断)打断,将其放在中断处理程序中执行。
d)其他所有任务,考虑放在下半部去执行。
(2)为什么要使用软中断?软中断作为下半部机制的代表,是随着SMP(share memory processor)的出现应运而生的,它也是tasklet实现的基础(tasklet实际上只是在软中断的基础上添加了一定的机制)。
软中断一般是“可延迟函数”的总称,有时候也包括了tasklet(请读者在遇到的时候根据上下文推断是否包含tasklet)。
它的出现就是因为要满足上面所提出的上半部和下半部的区别,使得对时间不敏感的任务延后执行,而且可以在多个CPU上并行执行,使得总的系统效率可以更高。
它的特性包括:a)产生后并不是马上可以执行,必须要等待内核的调度才能执行。
linux内核分析笔记----中断和中断处理程序中断还是中断,我讲了很多次的中断了,今天还是要讲中断,为啥呢?因为在操作系统中,中断是必须要讲的..那么什么叫中断呢,中断还是打断,这样一说你就不明白了。
唉,中断还真是有点像打断。
我们知道linux管理所有的硬件设备,要做的第一件事先是通信。
然后,我们天天在说一句话:处理器的速度跟外围硬件设备的速度往往不在一个数量级上,甚至几个数量级的差别,这时咋办,你总不能让处理器在那里傻等着你硬件做好了告诉我一声吧。
这很容易就和日常生活联系起来了,这样效率太低,不如我处理器做别的事情,你硬件设备准备好了,告诉我一声就得了。
这个告诉,咱们说的轻松,做起来还是挺费劲啊!怎么着,简单一点,轮训(polling)可能就是一种解决方法,缺点是操作系统要做太多的无用功,在那里傻傻的做着不重要而要重复的工作,这里有更好的办法---中断,这个中断不要紧,关键在于从硬件设备的角度上看,已经实现了从被动为主动的历史性突破。
中断的例子我就不说了,这个很显然啊。
分析中断,本质上是一种特殊的电信号,由硬件设备发向处理器,处理器接收到中断后,会马上向操作系统反应此信号的带来,然后就由OS负责处理这些新到来的数据,中断可以随时发生,才不用操心与处理器的时间同步问题。
不同的设备对应的中断不同,他们之间的不同从操作系统级来看,差别就在于一个数字标识-----中断号。
专业一点就叫中断请求(IRQ)线,通常IRQ都是一些数值量。
有些体系结构上,中断好是固定的,有的是动态分配的,这不是问题所在,问题在于特定的中断总是与特定的设备相关联,并且内核要知道这些信息,这才是最关键的,不是么?哈哈.用书上一句话说:讨论中断就不得不提及异常,异常和中断不一样,它在产生时必须要考虑与处理器的时钟同步,实际上,异常也常常称为同步中断,在处理器执行到由于编程失误而导致的错误指令的时候,或者是在执行期间出现特殊情况,必须要靠内核来处理的时候,处理器就会产生一个异常。
深⼊理解“软中断”前⾔软中断(softirq)导致 CPU 使⽤率升⾼也是最常见的⼀种性能问题所以软中断这个硬⾻头必须啃下去!回忆下什么是中断中断是系统⽤来响应硬件设备请求的⼀种机制它会打断进程的正常调度和执⾏然后调⽤内核中的中断处理程序来响应硬件设备的请求场景类⽐,加深印象⽐如说你订了⼀份外卖,但是不确定外卖什么时候送到,也没有别的⽅法了解外卖的进度,但是,配送员送外卖是不等⼈的,到了你这⼉没⼈取的话,就直接⾛⼈了;所以你只能苦苦等着,时不时去门⼝看看外卖送到没,⽽不能⼲其他事情;不过呢,如果在订外卖的时候,你就跟配送员约定好,让他送到后给你打个电话,那你就不⽤苦苦等待了,就可以去忙别的事情,直到电话⼀响,接电话、取外卖就可以了、打电话:其实就是⼀个中断,没接到电话的时候,你可以做其他的事情只有接到了电话(也就是发⽣中断),你才要进⾏另⼀个动作:取外卖中断的优势⼀种异步的事件处理机制,可以提⾼系统的并发处理能⼒中断运⾏时间短由于中断处理程序会打断其他进程的运⾏,为了减少对正常进程运⾏调度的影响,中断处理程序就需要尽可能快地运⾏如果中断要处理的事情很多,中断服务程序就有可能要运⾏很长时间中断处理程序在响应中断会临时关闭中断。
这就会导致上⼀次中断处理完成之前,其他中断都不能响应,也就是说中断有可能会丢失响应中断场景类⽐假如你订了 2 份外卖,⼀份主⾷和⼀份饮料,并且是由 2 个不同的配送员来配送。
这次你不⽤时时等待着,两份外卖都约定了电话取外卖的⽅式。
但是,问题⼜来了,当第⼀份外卖送到时,配送员给你打了个长长的电话,商量发票的处理⽅式。
与此同时,第⼆个配送员也到了,也想给你打电话。
但是很明显,因为电话占线(也就是关闭了中断响应),第⼆个配送员的电话是打不通的。
所以,第⼆个配送员很可能试⼏次后就⾛掉了(也就是丢失了⼀次中断)软中断中断处理过程分割为了解决中断处理程序执⾏过长和中断丢失的问题,Linux 会将中断处理过程分成两个阶段,也就是上半部和下半部上半部:快速处理中断,它在中断禁⽌模式下运⾏,主要处理跟硬件紧密相关的或时间敏感的⼯作下半部:延迟处理上半部未完成的⼯作,通常以内核线程的⽅式运⾏承上启下上⾯说到的响应中断场景上半部就是你接听电话,告诉配送员你已经知道了,其他事⼉见⾯再说,然后电话就可以挂断了下半部才是取外卖的动作,以及见⾯后商量发票处理的动作。
linux内核分析--中断的分类什么是中断Linux 内核需要对连接到计算机上的所有硬件设备进行管理,毫无疑问这是它的份内事。
如果要管理这些设备,首先得和它们互相通信才行,一般有两种方案可实现这种功能:轮询(polling)让内核定期对设备的状态进行查询,然后做出相应的处理;中断(interrupt)让硬件在需要的时候向内核发出信号(变内核主动为硬件主动)。
第一种方案会让内核做不少的无用功,因为轮询总会周期性的重复执行,大量地耗用 CPU 时间,因此效率及其低下,所以一般都是采用第二种方案。
对于中断的理解我们先看一个生活中常见的例子:QQ。
第一种情况:你正在工作,然后你的好友突然给你发送了一个窗口抖动,打断你正在进行的工作。
第二种情况:当然你有时候也会每隔 5 分钟就去检查一下 QQ 看有没有好友找你,虽然这很浪费你的时间。
在这里,一次窗口抖动就可以被相当于硬件的中断,而你就相当于 CPU,你的工作就是 CPU 这在执行的进程。
而定时查询就被相当于 CPU 的轮询。
在这里可以看到:同样作为 CPU 和硬件沟通的方式,中断是硬件主动的方式,较轮询(CPU 主动)更有效些,因为我们都不可能一直无聊到每隔几分钟就去查一遍好友列表。
CPU 有大量的工作需要处理,更不会做这些大量无用功。
当然这只是一般情况下。
好了,这里又有了一个问题,每个硬件设备都中断,那么如何区分不同硬件呢?不同设备同时中断如何知道哪个中断是来自硬盘、哪个来自网卡呢?这个很容易,不是每个 QQ 号码都不相同吗?同样的,系统上的每个硬件设备都会被分配一个 IRQ 号,通过这个唯一的 IRQ 号就能区别张三和李四了。
从物理学的角度看,中断是一种电信号,由硬件设备产生,并直接送入中断控制器(如 8259A)的输入引脚上,然后再由中断控制器向处理器发送相应的信号。
处理器一经检测到该信号,便中断自己当前正在处理的工作,转而去处理中断。
此后,处理器会通知 OS 已经产生中断。
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)需要这样一个结构。
中断处理程序下半部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就足够了,像网络这样对性能要求非常高的情况下才需要使用软中断。
一进程和进程调度1.进程1.1 什么是进程正在执行的程序代码的实时结果,即处于执行期的程序及相关资源。
系统进行资源分配和调度的基本单元Linux系统中的进程:交互式进程shell命令进程、文本编辑器批处理进程编译实时进程视频应用程序1.2 Linux下的进程结构内核将所有进程存放在进程链表,链表的每一项的类型为task_struct这个类型就称为进程描述符,一个进程描述符包含了具体进程的所有信息,包括进程的状态、进程标识值、进程间的关系、打开的文件信息等1.进程标识内核通过唯一的进程标识值PID来标识每一个来标志每一个进程PID存放在进程描述符中getpid() 获得当前进程的进程号getppid() 获得当前进程的父进程号2.进程的状态TASK_RUNNING 运行状态(运行就绪、正在运行)TASK_INTERRUPTIBLE 可中断的阻塞状态TASK_UNINTERRUPTIBLE 不可中断的阻塞状态TASK_TRACED 跟踪状态TASK_STOPPED 暂停状态设置当前进程的状态:set_current_state(current,state);进程家族树:Linux系统的进程之间存在继承关系,所有的进程都是PID为1的init进程的后代,内核在系统启动的最后阶段启动init进程。
1.3Linux 下进程的创建和终止1.创建fork() 拷贝当前进程创建一个子进程exec() 读取可执行文件并将其载入地址空间开始运行其中,fork()使用写时复制技术,避免拷贝大量用不到的数据,使系统具有快速执行能力2.终止do_exit() 释放与进程相关的资源,进程僵死不可运行,处于退出状态但仍保留了进程描述符,此时进程的存在只为父进程能获得它的信息wait() 终止进程,占用的所有资源被释放1.4Linux下的进程调度1.进程的优先级Linux采用两种不同的优先级范围1)nice值-20~+19 默认值为0 值越大优先级越低2)实时优先级可配置0~99 值越大优先级越高内核将进程分为两个级别: 普通进程和实时进程,任何实时进程的优先级都高于普通进程,实时优先级和nice 优先级处于互不相交的两个范畴2.时间片进程被抢占前持续运行的时间时间片过长系统对交互响应表现欠佳时间片过短明显增大进程切换带来的处理器耗时Linux的CFS调度器并没有直接分配时间片到进程,而是划分了处理器的使用比,它还会受到nice值得影响3.Linux下的进程调度Linux的调度器类主要实现两类进程调度算法:实时调度算法和完全公平调度算法(CFS)1)对实时进程的调度按优先级执行,一般不会被抢占。