linux中断机制和时钟_第1页
linux中断机制和时钟_第2页
linux中断机制和时钟_第3页
linux中断机制和时钟_第4页
linux中断机制和时钟_第5页
已阅读5页,还剩69页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Lecture8

LinuxInterruptandtimer中断机制中断基本知识异常处理外部中断处理中断的后半部分处理机制一、中断基本知识1.中断向量Intelx86系列微机共支持256种向量中断,按0~255编号,即赋予一个中断类型码,linux中称其为中断向量。所有的256种中断可分为中断和异常两大类。异常又分为故障和陷阱,它们的共同特点是既不使用中断控制器,又不能被屏蔽。中断又分为外部可屏蔽中断和外部非屏蔽中断。所有的I/O设备产生的中断请求均引起可屏蔽中断,而紧急事件引起的故障产生非屏蔽中断。非屏蔽中断的向量和异常的向量是固定的,而可屏蔽中断的向量可以通过对中断控制器的编程来实现。从0~31的向量对应于异常和非屏蔽中断从32~47的向量分配给屏蔽中断从48~255的向量用来标志软中断(由intn指令产生),

linux只用了一个:128(0x80)向量异常和非屏蔽中断0 除法出错 SIGFPE 故障 被0除1 调试 SIGTRAP 故障/陷阱 对程序进行逐步调试2 非屏蔽中断(NMI)3 断点 SIGTRAP 陷阱 由Int3断点指令引起4 溢出 SIGSEGV 陷阱 当into(checkforoverflow)指令被执行5 边界检查 SIGSEGV 故障 当bound指令被执行6 非法操作码 SIGILL 故障 当CPU检查到一个无效操作码7 设备不可用 SIGSEGV 故障 随着CR0的TS设置,ESCAPE或MMX指令被执行8 双重故障 SIGSEGV 故障 处理器不能串行处理异常引起9 协处理器段越界 SIGFPE 故障 因外部的数学协处理器引起的问题(仅用在80386)10 无效TSS SIGSEGV 故障 要切换到的进程具有无效的TSS11 段不存在 SIGBUS 故障 引用一个不存在的内存段12 栈段异常 SIGSEGV 故障 试图超越栈段界限,或由ss标志的段不在内存13 通用保护 SIGSEGV 故障 违反了Intelx86保护模式下的一个保护规则14 页异常 SIGSEGV 故障 寻址的页不在内存,或违反了一种分页保护机制15 Intel保留16 浮点出错 SIGFPE 故障 浮点单元用信号通知一个错误情况,如溢出17 对齐检查 SIGSEGV 故障 操作数的地址没有被正确地排列18~31Intel保留2.外设可屏蔽中断Intelx86通过两片中断控制器8259A来响应15个外部中断源,每个8259A可管理8个中断源。并非每个设备都可以向中断线(与中断控制器相连的每条线)上发中断信号,只有拥有了某条中断线的控制权,才可以向这条中断线上发送信号。中断线是非常宝贵的资源,必须采取只有当设备需要中断的时候才申请占用一个IRQ,或者是在申请IRQ时采用共享中断的方式。外设可屏蔽中断

32 IRQ0 时钟

33 IRQ1 键盘

35 IRQ3 tty2 36 IRQ4 tty1 37 IRQ5 XTWinchester 38 IRQ6 软驱

39 IRQ7 打印机

40 IRQ8 实时时钟

41 IRQ9 重定向的IRQ2 45 IRQ13 FPU异常

46 IRQ14 ATWinchester8259A执行的操作监视中断线,检查产生的IRQ信号如果在中断线上产生了一个IRQ信号把接收的IRQ信号转换成一个对应的向量。(IRQn的缺省向量是n+32)把这个向量存放在8259A的一个I/O端口,从而允许CPU通过数据总线读此向量。把产生的信号发送到CPU的INTR引脚——发出一个中断。等待,直到CPU确认这个中断信号,然后把它写进PIC的一个I/O端口,此时清INTR线返回第一步8259A对外部I/O请求的屏蔽可分为两种情况:

a清除EFLAGS的IF位,禁止所有外部的I/O中断请求

b中断控制器中有一个8位的中断屏蔽寄存器,每位对应于8259A中的一条中断线,如果要禁用某条中断线,把IRM相应位置1中断路由的逻辑图3.中断描述符表IDTIntel系统利用中断描述符表将中断向量和其处理程序对应起来。IDT是一个描述符数组,每一个元素由8个字节组成,叫做门描述符。每个中断向量对应一个门描述符。中断描述符表

DLP 段描述符的特权级 偏移量 入口函数地址的偏移量

P 段是否在内存中的标志 段选择符 入口函数所处代码段的选择符

D 标志位,1=32位,0=16位

XXX 三位门类型码

偏移量31~16|P|DPL|0DXXX|000|?????

段选择符|

偏移量15~0任务门类型码为101,门中包含一个进程的TSS段选择符,不使用偏移量,故不包含一个函数的入口地址,Linux中一般不用任务门进行任务切换。中断门

类型码为110,控制权通过中断门进入处理程序时关中断。中断门中的DPL为0,所有的中断处理程序都由中断门激活,并全部限制在内核态。中断时清IF标志,关中断以防止中断嵌套。陷阱门类型码为111,控制权通过陷阱门进入处理程序时不关中断,即IF标志位不变。系统门是Linux内核特别设置的,用来让用户态的进程访问Intel的陷阱门,DPL为3。通过系统门激活3,4,5,0x80中断。4.IDT的初始化Linux内核在系统的初始化阶段进行大量的初始化操作初始化可编程控制器8259A8259A内部有4个中断命令字寄存器,8259A初始化的目的是为了写入有关命令字,并利用8259A内部的相应寄存器锁存这些命令字,以控制8259A的工作。对IDTR进行初始化把IDT表的起始地址装入IDTR用setup_idt()函数填充IDT表中的256个表项在对IDT表进行了预初始化后,内核将在启用分页功能后对IDT表进行第二遍的初始化,用实际的陷阱和中断处理程序替换空的处理程序。注意:在Intel体系结构中提供了四个特权级,编号从0到3,其中0是最高特权级,3级是最低特权级。系统中每个段都有自己的特权级,系统中每个任务也都有自己的特权级。特权级低的任务不能直接调用高特权级的子程序,也不能存取高特权级的数据段。DPL——描述符的特权级CPL——当前任务的特权级注意:CPU为保护模式增设了一个IDTR,用来存放中断描述符表在内存的起始地址。

中断处理与当前进程有关。中断处理程序运行在当前进程的地址空间,使用的是当前进程的系统堆栈。32位基地址16位界限4716150中断描述符表寄存器IDTR5.中断和异常的硬件处理要求在一个中断和异常发生后,cpu将做以下事情:确定所发生的异常或中断向量i通过IDTR寄存器找到IDT表,读取IDT表第i项该中断处理程序所在段的DPL必须小于或等于当前代码段的CPL对于软中断,要求CPL<=中断或陷阱门的DPL硬件中断不检查特权级检查是否发生了特权级的变化,即是否需要切换堆栈发生中断时系统运行在核心态发生中断时系统运行在用户态二、异常

异常是cpu内部出现的中断,即在cpu在执行特定指令时出现的非法情况。非屏蔽中断是在计算机内部硬件出错时引起的异常情况,intel把非屏蔽中断作为一种异常来处理。在CPU处理一个异常处理程序时,不再为其他异常或可屏蔽中断请求服务。Linux异常中断向量在0~31之间,目前发布了大约20种。内核对异常处理程序的调用分成三个部分:在内核栈中保存寄存器的值先是顺序压入各寄存器的值,并调整栈顶满足pt_regs结构。(要注意当异常发生时,如果控制单元没有自动地把一个硬件错误代码插入到栈中。系统会自动执行一条push$0指令,在栈中垫入一个空值。如果错误代码已经压入堆栈,则接下来把异常处理函数的地址压入堆栈。)最后压入指向pt_regs的指针和错误代码。用call指令调用异常处理函数(使用当前栈顶的两个参数)通过ret_from_exception从异常退出,并进行异常善后处理。有无激活的底半处理,有则转入底半处理。被中断进程运行在核心态,简单弹出栈顶各寄存器的值,恢复被中断的进程。被中断进程运行在用户态,如当前进程需要调度,则运行调度函数,重新调度进程。如当前进程不需要调度,但如果当前进程上有待处理信号,则先处理信号再弹出寄存器值,并返回被中断进程。如果没有待处理信号则弹出寄存器值,返回被中断进程。

内核堆栈指针ESP用户栈的SS用户栈的ESPEFLAGS用户空间的CSEIP错误码或0函数地址DSEAXEBPEDIESIEDXECXEBX进入异常处理程序时内核堆栈示意图内核堆栈指针ESP用户栈的SS用户栈的ESPEFLAGS用户空间的CSEIP-1ESDSEAXEBPEDIESIEDXECXEBX错误码ESP异常处理程序被调用后内核堆栈示意图三、外部中断Linux把每个外部中断处理程序分为两个部分:固定部分:由系统所定义,设置在IDT中,不能随意修改。可变部分:由各个设备驱动程序定义,在设备初始化时设定,在不需要时可以将其清除或卸载。发生外部中断时,系统经过中断处理的固定部分进入可变部分。在处理外部中断的过程中,通常关掉中断,所以中断处理程序越短愈好。(一)固定部分外部中断初始化函数init_IRQ()中利用IRQn_interrupt创建0~15号中断门,并根据IRQ号填入IDT表中。每个外部中断处理程序的固定部分所做的工作为:将IRQ号压入堆栈将各通用寄存器的值压入堆栈(SAVE_ALL)

将中断返回地址ret_from_intr压入堆栈利用jmp指令跳转到do_IRQ()执行(do_IRQ根据堆栈中的IRQ号完成真正的中断处理)(二)可变部分由于外部中断处理程序具有可变部分,而且由于硬件限制,许多外部设备不得不共享同一个IRQ,并且各IRQ对应的处理程序可以在运行中动态改变。Linux为每一个IRQ设置了一个队列,即中断请求队列。对于224个中断向量,每一个IRQ,Linux都用一个irq_desc_t结构来描述,称为IRQ描述符,形成一个irq_desc[]数组。

typedefstruct{ unsignedintstatus; //中断线状态

hw_irq_controller*handler; //指向hw_interrupt_type描述符

structirqaction*action; //单链表指针

unsignedintdepth; //0表示可用,每用一次加1

spinlock_tlock; // }__cacheline_alignedirq_desc_t;1.可变部分的数据结构Status:描述IRQ中断线状态的一组标志#defineIRQ_INPROGRESS1#defineIRQ_DISABLED2#defineIRQ_PENDING4#defineIRQ_REPLAY8#defineIRQ_AUTODETECT16#defineIRQ_WAITING32handler:指向hw_interrupt_type描述符,该结构是对中断控制器的操作。

structhw_interrupt_type{//是对一个中断控制器的抽象,其主要内容是对中断控制器的操作

constchar*typename; //控制器的可读名

unsignedint(*startup)(unsignedintirq); //等同于enable void(*shutdown)(unsignedintirq); //等同于disable

void(*handle)(unsignedintirq); void(*enable)(unsignedintirq); // void(*disable)(unsignedintirq); //

void(*ack)(unsignedintirq); // void(*end)(unsignedintirq); // void(*set_affinity)(unsignedintirq,unsignedlongmask); // }typedefstructhw_interrupt_typehw_irq_controller;action:指向一个单项链表的指针,此链表是对中断服务例程进行描述的irqaction结构。depth;如果启用该中断线,depth则为0。如果禁用不止一次,则为一个正数。注意:disable_irq()和enable_irq()

对IRQ描述符的初始化由init_ISA_irqs()完成2.中断服务例程及描述符irqaciton中断服务例程描述符irqaction,描述了一个外部中断处理的可变部分。

structirqaction{ void(*handler)(int,void*,structpt_regs); //指向一个具体的中断服务例程

unsignedlongflags; //一组标志描述中断线与I/O设备之间的关系

unsignedlongmask; // constchar*name; //I/O设备名

void*dev_id; //指定I/O设备的主设备号和次设备号

structirqaction*next; }handler:指向一个具体I/O设备的中断服务例程,这是允许多个设备共享同一中断线的关键。

flags:用一组标志来描述中断线与I/O设备之间的关系:

SA_INTERRUPTSA_SHIRQSA_SAMPLE_RANDOMSA_PROBEname:I/O设备名

dev_id:指定I/O设备的主设备号和次设备号。

next:指向irqaction描述表链表的下一个元素。3.对数组irq_decsc所作的初始化

4.中断请求队列的初始化在设备驱动程序的初始化阶段,每个设备驱动程序都要创建自己的irqaction结构,通过request_irq()函数将对应的中断服务例程挂入中断请求队列。

intrequest_irq(unsignedintirq,void(*handler)(int,void*,structpt_regs*),unsignedlongirqflags,constchar*devname,void*dev_id)检查参数的合法性向内核内存管理器申请一块内存,用于建立irqaction结构根据参数填写申请到的irqaction结构调用函数setup_x86_irq,将填写好的irqaction结构挂到irq_desc[irq]的action队列上。setup_x86_irq(unsignedintirq,structirqaction*new)在数组irq_desc[]中找到参数irq对应的action队列如果队列不为空,说明有多个设备共享该IRQ号,检查共享的合法性,并将新irqaction结构挂在对应action队列的末尾。如果队列为空,则将irqaction结构挂在对应action队列的头部。并填写对应数组项的其它域。

5.释放中断处理程序利用free_irq()函数来完成

voidfree_irq(unsignedintirq,void*dev_id)

根据irq找到某条中断线,若该中断线是非共享的,则删除处理程序的同时禁用该中断线。若该中断线是共享的,则仅删除dev_id对应的处理程序,该中断线只有在删除了所有的处理程序才会被禁用。6.中断处理程序的执行外部中断处理函数do_IRQ()函数handle_IRQ_event()函数voiddo_IRQ(structpt_regsregs)从栈顶取出IRQ号根据取出的IRQ号从irq_desc[]数组中找到对应的hw_interrupt_type类型,并执行其handle子程序。handle执行完后,中断的上半部分已经完成。检查底半处理是否需要执行。do_IRQ执行完毕则返回。

staticvoiddo_8259A_IRQ(unsignedintirq,structpt_regs*regs)

向8259A发送信号,暂时禁止目前处理的IRQ中断清除irq_desc[irq].status中的IRQ_REPLAY和IRQ_WAITING位若IRQ的状态中包含IRQ_DISABLE|IRQ_INPROGRESS,则说明该IRQ被禁止或正在处理,则不能坐任何工作,返回。否则,将irq_desc[irq].status中加入IRQ_INPROGRESS位,并找到该IRQ对应的action队列。如果action队列为空,则返回调用handle_IRQ_event(),处理action队列。从handle_IRQ_event()返回,去掉IRQ标记中的IRQ_INPROGRESS位,表示该中断处理已完成。解除对该IRQ中断的禁用inthandle_IRQ_event(unsignedintirq,structpt_regs*regs,

structirqaction*action)调用函数irq_enter(cpu,irq),阻止进入底半处理对于慢速中断,在做上半部分处理时允许再次中断,故打开中断。进入循环,顺序调用action队列上的各个处理函数,完成真正的中断处理。关掉中断调用irq_exit(cpu,irq),允许进入底半处理。7.从中断返回do_IRQ的返回地址是ret_from_intr在ret_from_intr处检查被中断程序的运行模式若被中断程序运行在核心态,则弹出栈顶各寄存器的值并恢复该进程的执行。若被中断进程运行在用户态,则要视其是否需要调度和该进程上是否有信号来分别处理。8.自动探测IRQ号探测IRQ号的顺序P96probe_irq_on()函数probe_irq_off()函数四、中断处理的后半部分中断服务例程一般是在中断请求关闭的情况下执行的,而关中断时间过长,会导致cpu不能及时响应其他的中断请求,从而造成中断的丢失。故Linux在设计内核时,希望尽可能快地处理完中断,把更多的处理向后推迟。Linux定义了两种中断,快速中断和慢速中断。慢速中断本身可以再被中断,快速中断不允许再被中断。因此,内核把中断处理的可变部分分成两个部分,前半部分和后半部分,前半部分内核立即执行,而后半部分留着稍后处理。补充:对于后半部分通常在中断一返回就可以马上执行,且在后半部分运行时,允许响应所有的中断。1.bottomhalf(bh)机制与bh机制相关的数据结构intbh_mask_count[32];unsignedlongbh_active;unsignedlongbh_mask;void(*bh_base[32])(void);bh_mask_count[]是底半处理的屏蔽计数,每个底半处理对应其中的一项。指针数组bh_base[]的每一项都指向一个底半处理程序。bh_active表示底半程序是否被激活。bh_mask表示是否安装了底半处理程序。他们中的每一位都对应着数组中一项。只有在安装并激活了第N个底半处理时,才能调用第N个底半处理程序bh的初始化由init_bh()完成将相应的底半处理程序注册到bh_base[]中的操作。inlinevoidinit_bh(intnr,void(*routine)(void))bh卸载卸载已注册的底半处理

inlinevoidremove_bh(intnr)将bh_mask中的相应位清0,表示该底半处理不可再用清除在数组bh_base中注册的处理函数禁止和恢复bhinlinevoiddisable_bh(intnr)将变量bh_mask的nr位清0,表示底半处理不可再用。将bh_mask_count[nr]加1inlinevoidenable_bh(intnr)将bh_mask_count[nr]减1如果其为0,则将变量bh_mask的nr位置1,表示底半处理可用。bh的执行首先利用mark_bh(intnr)激活bh_active中的nr位。每次执行完do_IRQ()中的中断服务例程以后,每次系统调用结束之前,以及当被中断进程运行在用户态且需要调度,在作进程调度之前,在do_bottom_half()中执行相应的bh函数,且do_bottom_half()对bh的执行是在关中断的情况下执行的。在do_bottom_half()中真正的底半操作由run_bottom_half()完成调用宏get_active_bhs(),取出激活且安装的底半处理。调用宏clear_active_bh(),将上一步取出项所对应的变量bh_active中的激活位清0根据取出的激活位,顺序执行在bh_base[]中注册的底半处理操作bh机制的特点:具有“串行化”的特点,不适合于多cpu结构。2.软中断机制软中断机制也是推迟内核函数的执行,与bh函数严格的串行执行相比,软中断在任何时候都不需要串行化,同一个软中断的两个实例完全可能在两个CPU上同时执行。因此软中断是可重入的,这给网络部分带来了好处。软中断本身是一种机制,既包含了bh机制,也包含了tasklet机制。软中断的执行首先用open_softirq进行初始化,然后通过softirq_init()执行软中断。一个注册的软中断必须在标记以后才会被执行。通常中断处理程序会在返回前标记它的软中断,使其在稍后执行。内核在do_IRQ()中执行完一个中断请求队列中的中断服务例程以后,都要检查是否有软中断请求在等待执行。在检测到软中断请求后,在调用do_softirq()来执行软中断服务例程。软中断机制的特点其执行是“并行的”,可以重入的,即允许不同的cpu同时进入对软中断服务例程的执行,但不能让它们相互干扰。3.tasklet机制是建立在软中断机制的基础上,与bh机制类似。tasklet的初始化方法很多,可以静态创建,也可以动态创建。动态创建的方法之一:由tasklet_init()完成tasklet的使用通过调用tasklet_schedule(),激活它的tasklet_struct中指针所指向的服务程序。在tasklet被调用以后,只要有可能就尽可能早的运行,若某个tasklet还没得到运行机会之前又有一个相同的tasklet又被调度了,经过检查重复后,他只运行一次。若它已开始运行,那么新的tasklet会被重新调度并且再次运行。tasklet的特点同一个tasklet只能运行在一个cpu上,而不同的tasklet可以同时运行在不同的cpu上,即tasklet是非重入的。IRQ锁软IRQ锁 有时不希望系统做底半处理,如系统正在做底半处理时被中断,此时不希望在中断的上半部分处理完以后再次进入底半处理。unsignedintlocal_bh_count[NR_CPUS]start_bh_atomic(void)用来禁止底半处理

end_bh_atomic(void)恢复底半处理

softirq_trylock(cpu)判断是否允许进入底半处理

softirq_endlock(cpu)允许底半处理以上4个函数是在关中断情况下执行.硬IRQ锁 除了软件IRQ锁以外,Linux还提供硬IRQ锁,一般情况下,硬件的开中断和关中断不受限制,但在特殊情况下必需限制硬件的开关中断,如在做中断的上半部分处理时的开中断就必需限制。硬IRQ锁通过unsignedintlocal_irq_count[NR_CPUS]来实现。IRQ锁的作用 底半处理既使用了软IRQ锁,也使用了硬IRQ锁。实际上,定义IRQ锁的目的主要是为了控制底半处理的重入。Linux的时钟管理时钟中断时钟中断处理过程底半处理系统时间更新进程时间片定时器中断和时钟中断时钟中断是需要操作系统内核特别处理的一个外部中断时钟中断是操作系统的脉搏:维护系统时间、统计运行数据、设计计时时钟、促使进程切换、监督系统工作时钟中断时间系统(即时钟)是计算机系统非常重要的组成部分PC机有两个时钟源:实时时钟(RTC)和OS时钟RTC也叫CMOS时钟,是主板上的一块靠电池供电的晶片(晶振),独立于OS,也称为硬件时钟,为计算机提供计时标准,是最底层的时钟数据OS时钟由硬件(定时/计数器)和软件(时钟中断处理程序)组成。定时/计数器从RTC接收输入脉冲,并计数,每次计数到期就产生一个输出脉冲,再从头计数

可编程定时/计数器由计数硬件和通信寄存器组成,通信寄存器负责在计数硬件和操作系统之间通信时钟中断产生过程IRQ08259A-1中断控制器8253/8254定时/记数器RTC晶振1.193180MHzOut0Out1Out2DRAM刷新扬声器接CPU中断输入端时钟中断处理过程OS注册时钟中断处理程序timer_interrupt1、定时/计数器产生输出脉冲时,中断处理器送出中断信号,CPU根据IRQ号查中断描述符表IDT,找到并执行中断处理程序IRQ00_interrupt2、跳到do_IRQ3、do_IRQ执行handle程序do_8259A_IRQ4、do_8259A_IRQ执行timer_interrupt5、timer_interrupt调用do_timer完成上半部分处理。do_timer定义如下:voiddo_timer(structpt_regs*regs){ (*(unsignedlong*)&jiffies)++;lost_ticks++; mark_bh(TIMER_BH);if(!user_mode(regs))lost_ticks_system++; if(tq_timer) mark_bh(TQUEUE_BH);}6、timer_interrupt返回后,do_8259A_IRQ返回到do_IRQ7、底半处理8、返回到ret_from_intr,这里或者返回到被中断的进程,或者启动调度程序,完成新一轮调度底半处理1、时钟底半处理函数timer_bh定义2、时钟任务队列处理函数tqueue_bh定义3、底半处理的工作(1)更新系统时间(2)更新当前进程时间片(3)处理老定时器(4)处理新定时器(5)处理时钟任务队列系统时间系统时间结构

structtimeval{inttv_sec;//秒

inttv_usec;//微秒

}初始化:函数time_init从CMOS时钟取出当前时间,通过函数mktime转化成自1970-01-0100:00:00以来的秒数,存入全局变量xtime.tv_sec中,将xtime.tv_usec初始化为0累计系统时间

voidupdate_wall_time(unsignedlongticks)

其中ticks是从上次时钟中断底半处理以来已经过去的tick数,一般为1。

update_wall_time完成的工作Xtime.tv_usec+=tick+time_adjust_step;根据变量time_adj、time_phase调整xtime.tv_usec;Ticks--;如果ticks>0,则转第一步调整xtime值,累计秒数,减少微秒数:if(xtime.tv_usec>=1000000){xtime.tv_usec-=1000000;xtime.tv_sec++;second_overflow();}时间的转换和修改

LINUX提供多个系统调用来转换和设置系统时间更新进程时间片反映进程运行情况,若时间片用完则通知当前进程放弃CPU通过函数update_process_times更新时间片(1)计算从上次底半处理后在用户态发生的时钟中断次数:user=ticks-system;

(2)如果当前进程不是0号进程,则a.进程时间片减ticks:current->counter-=ticks;b.若时间片已用完,则要求进程放弃CPU:

if(p->counter<0){p->counter=0;p->need_resched=1;}c.根据user调整变量kstat中的统计信息

(3)调用函数update_one_process修改当前进程的其它与时间相关的信息函数update_one_processa.累计进程在当前CPU消耗的用户态时间:

p->per_cpu_utime[cpu]+=user;b.累计进程在当前CPU消耗的核心态时间:

p->per_cpu_stime[cpu]+=system;c.累计进程消耗的用户态时间:

p->times.tms_utime+=user;d.累计进程消耗的核心态时间:

p->times.tms_stime+=system;e.若进程消耗总时间超过当前时间界限,则在总量达到整秒时向进程发送SIGXCPU信号f.若进程消耗总时间超过最大时间界限,则向进程发送SIGKILL信号,强行杀死进程

h.若进程定义有virtual定时器,则根据消耗的用户态时间处理它

i.若进程定义有prof定时器,则根据消耗的用户态和核心态时间处理它定时器在进程运行时,系统提供的virtual和prof定时器可以实现定时为了在任何时候都能够定时,LINUX提供两类根据系统时间定时且与进程状态无关的定时器:老定时器和新定时器老定时器结构

structtimer_struct{unsignedlongexpires;//终止时间

void(*fn)(void);//到期要执行的函数

}最多有32个老定时器系统定义一个位图timer_active来标识已注册并处于活动状态的定时器,如果某位被置1则相应的定时器活动通过以下函数在底半处理中检查并处理老定时器:

run_old_timers

顺序搜索位图,发现某位被设置就检查是否到期。如果到期就清除位图中该定时器的标记,表示处理完成;执行定时器指定操作tp->fn();每处理一个定时器就开一次中断sti()新定时器新定时器结构

structtimer_list{structtimer_list*next;structtimer_list*prev;unsignedlongexpires;//终止时间

unsignedlongdata;void(*function)(unsignedlong);};其中data是传给处理函数function的参数next和prev两个指针将定时器连成双向链表tvecstv5tv4tv301234indexindextimer_l

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论