中断、异常、抢占内核(抄录)

简介: 中断、异常、抢占内核====================中断信号分类-------------------中断信号是一个统称,统称那些改变CPU指令执行序列的事件。但它又分为两种:一种是同步的,没那么突然,因为它只在一个指令的执行终止之后才发生,书中依从Intel的惯例,称为异常(Exception)。
中断、异常、抢占内核
====================
中断信号分类
-------------------
中断信号是一个统称,统称那些改变CPU指令执行序列的事件。但它又分为两种:
一种是同步的,没那么突然,因为它只在一个指令的执行终止之后才发生,书中依从Intel的惯例,称为异常(Exception)。一般是编程错误(一般的处理是发信号)或者内核必须处理的异常情况(内核会采取恢复异常所需的一些步骤);
一种是异步的,突然一些,因为它是由间隔定时器和I/O设备产生的,只遵循CPU时钟信号,所以可能在任何时候产生,书中也依从Intel的惯例,称为中断(Interrupt)。
内核控制路径
------------------
内核在允许中断信号到来之前,必须先准备好对它们的处理,也就是适当地初始化中断描述符表(Interrupt Descriptor Table, IDT)。
中断信号一来,CPU控制单元就自动把当前的程序计数器(eip、cs)和eflags保存到内核stack,然后把事先与发生的中断信号类型关联好的处理程序的地址(保存在IDT中)放进程序计数器。这时,内核控制路径(kernel control path)横空出世。
什么是内核控制路径?它是不是一个进程?不是。内核进程?也不是。它虽然也需要切换上下文,需要保存那些它可能使用的寄存器的并在返回时恢复,但这是一个非常轻的上下文切换。它诞生的时候并没有发生进程切换,处理中断的主语仍然是中断发生时正在执行的那个进程。那个进程就像突然被内核抓进了一间小屋做事,或者突然潜入了水(内核)里不见踪影,但它仍然在使用分配给它的那段时间片。
有趣的是,如果一个进程还在处理一个异常的时候,分配给它的时间片到期了,会发生什么事情呢?这取决于有没有启用内核抢占(Kernel Preemption),如果没有启用,进程就继续处理异常,如果启用了,进程可能会立即被抢占,异常的处理也就暂停了,直到schedule()再度选择原先那个进程(注意:内核处理中断的时候,必然会禁用内核抢占,所以这里才说是异常)。
中断信号处理的约束
----------------------------
中断信号处理需要满足下面三个严格的约束:
1)中断处理要尽可能块地完成、返回。因此只执行关键而紧急的部分,尽可能把更多的后续处理过程仅仅标志一下,放到之后再去执行。
2)一个中断还在处理的时候,另外一个中断可能又来了,这个时候最好能先放下手中的处理,先去处理新的中断,然后在回头来接着处理这个中断,这称之为中断和异常处理程序的嵌套执行(nested execution),或者说是内核控制路径的嵌套执行。要实现这一点,有一点必须满足,那就是中断处理程序运行期间不能阻塞,不能发生进程切换。
如果对异常的种类做一番思考,就会发现,异常最多嵌套两层,一个由系统调用产生,一个由系统调用执行过程中的缺页产生(这时必然挂起当前进程,发生进程切换)。与之相反,在复杂的情况下,中断产生的嵌套则可能任意多。
3)内核中存在一些临界区,在这些临界区,中断必须被禁止。中断处理程序要尽可能地减少进入临界区的次数和时间,为了内核的响应性能,中断应该在大部分时间都是启用的。
异常的种类
---------------
异常有很多种,其中比较有趣的有:
img_dd27b4c2f9a5d543dc47bfb2ad88b0ab.jpg
中断描述符
---------------
Intel 80x86 CPU认得三种中断描述符,Linux为了检验权限,将其细分为:
Interrupt Gate, DPL = 0的中断门,set_intr_gate(n,addr),所有中断
System Interrupt Gate,DPL = 3的中断门,set_system_intr_gate(n,addr),int3异常
System Gate,DPL = 3的陷阱门,set_system_gate(n,addr),into、bound、int $0x80异常
Trap Gate, DPL = 0的陷阱门,set_trap_gate(n,addr),大部分异常
Task Gate, DPL = 0的任务门,set_task_gate(n,gdt),double fault异常
异常处理的标准结构
-----------------------------
用汇编把大多数寄存器的值保存到kernel stack;
用C函数处理异常
通过ret_from_exception( ) 函数退出处理程序.
I/O中断处理的标准结构
---------------------------------
将IRQ值和寄存器值保存到kernel stack;
给服务这条IRQ线的PIC发送应答,从而允许它继续发出中断;
执行和所有共享此IRQ的设备相关联的ISR;
通过跳转到ret_from_intr( ) 的地址结束中断处理。
IRQ(Interrupt ReQuest)线(IRQ向量)的分配
-------------------------------------------------------------
IRQ共享:几个设备共享一个IRQ,中断来时,每个设备的中断服务例程(Interrupt Service Routine,ISR)都执行,检查一下是否与己有关;
IRQ动态分配:IRQ可以在使用一个设备的时候才与一个设备关联,这样同一个IRQ就可以被不同的设备在不同时间使用。
中断向量中,0-19用于异常和非屏蔽中断,20-31被Intel保留了,32-238这个范围内都可以分配给物理IRQ,但128(0x80)被分配给用于系统调用的可编程异常。
延后的工作谁来做?
--------------------------
首先是两种非紧迫的、可中断的内核函数——可延迟函数(deferrable functions ),然后是通过工作队列(work queues )来执行的函数。
软中断(softirq)是可重入函数而且必须明确地使用自旋锁保护其数据结构;tasklet在软中断基础上实现,但由于内核保证不会在两个CPU上同时运行相同类型的tasklet,所以它不必是可重入的。
六种软中断
Softirq
Index (priority)
Description
HI_SOFTIRQ
0
Handles high priority tasklets
TIMER_SOFTIRQ
1
Tasklets related to timer interrupts
NET_TX_SOFTIRQ
2
Transmits packets to network cards
NET_RX_SOFTIRQ
3
Receives packets from network cards
SCSI_SOFTIRQ
4
Post-interrupt processing of SCSI commands
TASKLET_SOFTIRQ
5
Handles regular tasklets
内核会在一些检查点(适宜的时候,其中有时钟中断)检查挂起的软中断,用__do_softirq()执行它们。__do_softirq()会循环若干次,以保证处理掉一些在处理过程中新出现的软中断,但如果还有更多新挂起的软中断,__do_softirq()就不管了,而是调用wakeup_softirq()唤醒每CPU内核进程ksoftirqd/n(这样就可以被调度,而不会一直占着CPU),来处理剩下的软中断。
这种做法是为了解决一个矛盾:与网络相关的软中断是高流量的,也是对实时性有一定要求的。但是如果do_softirq()为了实时性一直处理它们,就会一直不返回,结果用户程序就僵在那里了;如果do_softirq()处理完一些软中断就返回,不论这中间机器有无空闲,直到下一个时钟中断才又处理其余的,网络处理需要的许多实时性就得不到保证。现在的做法,唤醒内核进程,让它在后台调度,由于内核进程优先级很低,用户程序就有机会运行,不会僵死;但如果机器空闲下来,挂起的软中断很快就能被执行。
tasklet则多用于在I/O驱动程序的开发中实现可延迟函数。
但是,可延迟函数有一个限制,它是运行在中断上下文的,它执行时不可能有任何正在运行的进程,它也不能调用任何可阻塞(从而会休眠)的函数。这就是工作队列的意义所在。工作队列把需要执行的内核函数交给一些内核进程来执行。
处于效率的考虑,内核预定义了叫做events的工作队列,内核开发者可以用schedule_work族函数随意呼唤它们。
内核抢占(Kernel Preemption)
-----------------------------------------
本章在很多地方都涉及到了内核抢占,我觉得还是将内核抢占在本章的笔记记完,不必像原书那样等到内核同步一章了。
在非抢占内核的情形,一个执行在内核态的进程是不可能被另外的进程取代的(进程切换);而在抢占内核的情形,是有可能的:但只有当内核正在执行异常
处理程序(尤其是系统调用),而且内核抢占没有被显式禁用的时候,才可能抢占内核。
一个例子:当A在处理异常的时候,一个中断的处理程序唤醒了优先级更高的B,在抢占内核的情形,就会发生强制性进程切换。这样做的目的是减少dispatch latency,即从进程(结束阻塞)变为可执行状态到它实际开始运行的时间间隔,降低了它被另外一个运行在内核态的进程延迟的风险。
进程描述符中的thread_info字段中有一个32位的preempt_counter字段,0-7位为抢占计数器,用于记录显式禁用内核抢占的次数;8-15位为软中断计数器,记录可延迟函数被禁用的次数;16-27为硬中断计数器,表示中断处理程序的嵌套数(irq_enter()递增它,irq_exit()递减它);28位为PREEMPT_ACTIVE标志。只要内核检测到preempt_counter整体不为0,就不会进行内核抢占,这个简单的探测一下子保证了对众多不能抢占的情况的检测。
说明:
1)为了避免在可延迟函数访问的数据结构上发生的竞争条件,最简单直接的方法是禁用中断,但禁用中断有时太夸张了,所以有了禁用可延迟函数这回事。
2) PREEMPT_ACTIVE标志的本意是说明正在抢占,设置了之后preempt_counter就不再为0,从而执行抢占相关工作的代码不会被抢占。
它可被非常tricky地这样使用:
preempt_schedule()是内核抢占时进程调度的入口,其中调用了schedule()。它在调用schedule()前设置PREEMPT_ACTIVE标志,调用后清除这个标志。而schedule()会检查这个标志,对于不是TASK_RUNNING(state != 0)的进程,如果设置了PREEMPT_ACTIVE标志,就不会调用deactivate_task(),而deactivate_task()的工作是把进程从runqueue移除。
你可能会疑惑,为什么要预防已经不在RUNNING状态的进程从runqueue中移除?设想一下,一个进程刚把自己标志为TASK_INTERRUPTIBL,就被preempt了,它还没来得及把自己放进wait_queue中...这个时候当然要让它回头接着运行,直到把自己放进wait_queue然后自愿进程切换,那时才可以把它从runqueue中移除。
在面对内核的时候,思维不能僵化在操作系统提供给用户的进程切换的抽象中,而要想象一个永不停歇运行着的、虽然有意识地跳来跳去的指令流的。所以,没有标志为RUNNING不意味就不会还剩下一些(比如处理状态转换的)代码需要执行哦。
通过这个标志,保证了被抢占的进程将可以被正确地重新调度和运行。
在中断、异常、系统调用返回过程中也会设置PREEMPT_ACTIVE标志。
注:中断或者中断嵌套不会导致进程的切换,抢占则必须发生切换。
目录
相关文章
|
1月前
|
Java API 调度
线程的中断(interrupt)机制
线程的中断(interrupt)机制
29 1
|
2月前
|
资源调度 调度 UED
CPU执行系统调用时发生中断,操作系统还能切回中断前的系统调用继续执行吗?
系统调用服务例程在执行过程中,通常不会被中断。系统调用服务例程的执行是一个原子操作,即在执行期间不会被中断。这是为了确保在系统调用服务例程执行期间对内核数据结构的一致性和完整性。
|
3月前
|
编译器 C语言 芯片
内核里的中断
内核里的中断
34 0
|
8月前
|
调度
中断异常和系统调用
中断异常和系统调用
95 0
|
6月前
|
传感器 调度
什么是中断系统?
一、什么是中断系统 中断系统是计算机系统中的一种机制,它允许外部设备和程序请求处理器的注意力,以便进行特定的操作。当一个中断请求被触发时,处理器会暂停当前正在执行的程序,转而执行与中断相关的程序或服务例程。中断系统可以提高计算机系统的效率和响应速度,因为它允许处理器在等待某些事件的同时执行其他任务。常见的中断包括硬件中断(例如键盘输入、鼠标移动、网络数据传输等)和软件中断(例如操作系统调度、系统调用等)。 二、中断系统的特点 中断系统具有以下特点: 1. 实时性:中断系统能够及时响应外部设备的请求,提高计算机系统的响应速度和效率。 2. 可靠性:中断系统能够保证中断请求的可靠性,确保外部设备的
188 0
|
7月前
|
存储 缓存 Linux
RISC-V SiFive U54内核——中断和异常详解
RISC-V SiFive U54内核——中断和异常详解
|
安全 Java Unix
四、操作系统的启动,中断,异常和系统调用
四、操作系统的启动,中断,异常和系统调用
四、操作系统的启动,中断,异常和系统调用
|
缓存 编译器 Linux
CPU中断控制和并发处理的内核解析
CPU中断控制和并发处理的内核解析
CPU中断控制和并发处理的内核解析
|
监控 Java
一文了解JAVA线程的中断(Interrupt)机制
一文了解JAVA线程的中断(Interrupt)机制
858 0
一文了解JAVA线程的中断(Interrupt)机制
|
存储 Linux 程序员
1.1.5操作系统(中断和异常,系统调用)
中断 1.中断的作用 2.中断的分类 3.外中断的处理过程 系统调用 1.什么是系统调用,有何作用? 2.系统调用与库函数的区别 3.系统调用过程
1.1.5操作系统(中断和异常,系统调用)