windows内核开发学习笔记三十九:内核概念之中断和异常

        中断(interrupt)是处理器与外部设备打交道的重要途经;而异常(exception)则是处理器的正常指令流在执行过程中产生一些特殊事件,需要紧急处理才能继续原来的指令流。它们都会打断一个正常的指令流,但区别在于,中断的发生与当前指令流并无实质的联系,而异常则是当前指令流执行的直接结果。而且,中断是异步的,而异常是同步的。

        尽管中断和异常的触发来源和方式不相同,Intel x86处理器内部使用同一套陷阱机制来处理中断和异常,它利用IDT(Interrupt Descriptor Table,中断描述表),将每个中断或异常与一个处理该中断或异常的服务例程联系起来,因而一旦中断或者异常发生,该服务例程即被执行。Windows在此硬件机制的基础上,又提供了更为灵活的软件机制,允许设备驱动程序为特定的中断向量添加它的中断服务例程(ISR,Interrupt Service Routine)。一个中断向量允许链接多个中断对象(interrupt object),这里中断对象是一种封装了中断服务例程的内核对象。当中断发生时,这些中断对象中的服务例程都有机会处理该中断。通过中断对象机制,设备驱动程序可以在不操纵IDT的情况下加入它们的中断服务例程,另一方面,多个硬件设备也可以共享同样的硬件中断向量。

        中断控制器(如APIC)允许设定每一个硬件中断的优先级,但windows并没有使用中断控制器的优先级,而是规定了一套软件中断优先级,称为中断请求级别(IRQL,Interrupt Request Level)。在Intel x86系统中,windows使用0~31来表示IRQL,数值越大,优先级越高。处理器在运行时总是有一个当前IRQL,如果发生中断时,中断源的IRQL等于或者低于当前级别,则该中断被屏蔽,直到处理器的IRQL降下来为止。

  • IRQL=0表示普通的线程,称为PASSIVE_LEVEL或被动等级别,它的优先级最低,可被任何其他级别的中断打断;
  • IRQL=1表示异步过程调用(APC,Asynchronous Procedure Call),称为APC_LEVEL,它仅仅比PASSIVE_LEVEL高,因此,在一个线程中插入一个APC对象可以打断该线程的执行;
  • IRQL=2表示处理器正在做以下两件事情之一:正在进行线程调度,比如选择新的线程;正在处理一个硬件中断的后半部分(不那么紧急的部分),在windows中,这被称为延迟过程调用(DPC,Deferred Procedure Call)。因此IRQL为2也被称为DISPATCH/DPC级别,或者简单地称为DISPATCH_LEVEL。
  • 3~26是设备IRQL;
  • 27~31是一些特殊的硬件中断,包括时钟中断、处理器间中断等,它们都是硬件中断。

        DPC是一个重要的概念,它的IRQL等于DISPATCH_LEVEL,高于PASSIVE_LEVEL和APC_LEVEL,因此它优先于任何一个与线程相关函数,也屏蔽了线程调度;同时又低于所有硬件中断,所以它不会屏蔽任何一个硬件中断。之所以称为“延迟的”过程调用,是因为它往往被用来执行一些相对于当前高优先级的任务来说不那么紧急的事情,例如,硬件中断服务例程可以把一些相对不紧急的事情放到一个DPC对象中处理,从而缩短处理器停留在高IRQL的时间。在windows内核中,DPC的一个典型用法的定时器(timer)的实现,在时钟中断服务例程中,它负责更新中断时间、系统时间,以及当前线程的时间信息等,并判断系统的定时器数组中是否有定时器到期,若有则发出DISPATCH_LEVEL的软中断请求。定时器到期是在DPC交付(deliver)过程中处理的,定时器被当作一种特殊的DPC对象而交付执行。

        与DPC不同的是,APC是线程相关的例程,它们只能在特定的线程环境中被执行,因而也一定在特定的地址空间中被执行。由于APC的IRQL高于被动级别,所以APC优先于线程本身的指令流。当一个线程获得执行权时,它的APC例程会被立刻被执行。这一特性使得APC非常适合于实现各种异步通知事件,例如,I/O的完成通知可以用APC来实现。

        异常是程序指令流执行过程中的同步处理过程,既可以由处理器硬件产生,也可以由指令流软件产生。在Intel x86处理器中,异常也是通过IDT表分发的。在IDT表中,0~0x1f之间的中断向量是Intel保留的,除了2号中断向量保留给NMI(nonmaskable interrupt,不可屏蔽中断)以外,其他已经定义的中断向量都是针对各种条件所引发的异常的。windows为所有需要处理的异常都提供了异常处理器(exception handler,即异常处理例程),有些异常直接由系统内核处理,比如页面错误(0x0e号异常)由虚拟内存管理器接管;有些异常则需要交给当前线程或windows子系统的代码(内核模式或者用户模式)来处理,一旦异常发生条件消失,则异常处理器返回,原来的指令流继续执行。

         内核模式和用户模式的代码都有可能发生异常,根据发生异常时处理模式的不同,windows的异常分发(exception dispatch)过程也有所不同。内核模式异常处理相对简单一些,异常分发器首先将异常交给内核测试器来处理,若不存在内核调试器或者内核调试器没有处理该异常,则尝试分发到一个基于帧的异常处理器(frame-based exception handler)。基于桢的异常处理是一种异常处理技术,它将异常处理与帧栈(stack frame)关联起来,因而当发生异常时,异常分发器将根据当前栈中的栈帧来查找与之关联的异常处理器,如果未能找到这样的异常处理器,则异常分发器会将该异常再次交给内核调试器,若这一次该异常仍未能被处理,则认为是一个严重的错误,系统崩溃。

        用户模式的异常分发过程要复杂一些。异常分发器首先判断进程的调试端口是否有效,若有效,则发送消息至调试端口,然后等待应答,否则将异常交给内核调试器。如果异常仍未得到处理,则将控制转到用户模式下,由用户模式的异常分发器(ntdll.dll中的KeUserExceptionDispatcher函数)寻找一个基于帧的异常处理器。如果用户模式下该异常仍未得到处理,则控制再次回到内核模式下。这一次内核模式的异常处理器首先尝试调试端口,若遗产仍未被处理,则再尝试当前进程的异常端口,连接异常端口的是Windows子系统,因此,windows子系统在异常处理的最后时刻有机会处理他所属进程的异常。如果它不能处理此异常,则该进程被终止。

       中断和异常是操作系统的底层核心机制,它们既涉及处理器的硬件特性,也跟操作系统的并发性管理和代码的错误处理有关。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jyl_sh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值