AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > VC编程

Win32 核心 DPC 设计思想和实现思路浅析

51自学网 2015-08-30 http://www.wanshiok.com

x86架构设计在上是基于中断思想的,因而从DOS到Win32,操作系统中大量使用中断的概念来表达异步操作的行为。但与DOS下独占的情况不同,Win32下需要由系统对多任务进行调度,因此中断响应代码必须尽可能地简单,并且尽快的将控制权交还给系统。虽然这样一来系统调度的响应速度和实现过程方便了,但还是有很多功能需要在中断响应中完成。为此,Win32核心提供了DPC(Deferred Procedure Call)和APC(Asynchronous Procedure Call)两个IRQL特殊的软件中断级别,用于实现延迟和异步的过程调用。
  从IRQL分层来说,DPC和APC是介于较高级别的设备中断和最低级别的Passive中断之间,由操作系统用于完成特殊方法调用的中断级别。与处理硬件操作的设备中断和更高级别的时钟、处理器中断不同,这两级中断纯粹是为了实现功能调用异步性而设计实现的,因此操作系统本身也对它们具有很强的依赖型。APC这里暂且不讨论,以后有机会再写篇文章专门讨论 :)

  DPC在功能上可以理解为ISR(Interrupt Service Routine)的一部分。只是因为ISR为了尽量简单和返回控制权给操作系统,而将一部分功能剥离出来放入相应DPC中,延迟调用。因为DPC的IRQL仅在APC和Passive中断之上,所以系统可以从容地处理完高级别的中断后,再在DPC一级慢慢处理积累起来的相对并不那么紧急功能。
  DPC在使用上可以理解为一个回调函数的封装对象。系统本身或者设备驱动程序,在合适的地方如设备驱动程序的AddDevice函数或DispatchPnP函数处理IRP_MN_START_DEVICE请求时,初始化一个DPC对象;在ISR中判断是否需要进一步处理中断,是则请求将DPC对象插入到系统DPC队列中;系统处理完高IRQL后,会在IRQL DISPATCH_LEVEL级别慢慢处理DPC队列中的DPC对象;每个DPC对象封装的回调函数,会使用同时封装的调用参数,被系统调用,完成在ISR中来不及完成的工作;如果需要进一步的工作,还可以继续请求插入DPC对象到DPC队列中。

  DPC对象从最终用户角度有两种:DpcForIsr和CustomDPC。前者是与设备驱动对象(Device Object)绑定的;后者则由驱动自行维护。但从实现上来说,只有一种DPC对象存在,DpcForIsr所涉及的维护函数,实际上都是对CustomDPC的一个封装而已。

  我们首先来看看初始化DPC对象的实现。KeInitializeDpc函数(ntos/ke/dpcobj.c:39)完成具体的DPC对象的初始化,实际上就是填充一个内存结构KDPC(ntos/inc/ntosdef.h:331)。


以下为引用:

//
// Deferred Procedure Call (DPC) object
//

typedef struct _KDPC {
  CSHORT Type;
  UCHAR Number;
  UCHAR Importance;
  LIST_ENTRY DpcListEntry;
  PKDEFERRED_ROUTINE DeferredRoutine;
  PVOID DeferredContext;
  PVOID SystemArgument1;
  PVOID SystemArgument2;
  PULONG_PTR Lock;
} KDPC, *PKDPC, *RESTRICTED_POINTER PRKDPC;




  Type 表示此内核对象的类型,在KOBJECTS枚举类型(ntos/inc/ke.h:122)中定义,缺省为 DpcObject = 0x13。此外WinXP/2003新增了一种ThreadedDpcObject = 0x18
  Number 在多处理器环境下用于指定此DPC对象加入到哪个处理器的DPC队列中,我们等会讨论多处理器时详细描述。缺省为 0
  Importance 表示此DPC对象的重要性,在KDPC_IMPORTANCE枚举类型(ntos/inc/ntosdef.h:321)中定义,缺省为 MediumImportance = 1
  DpcListEntry 是用于维护DPC队列的链表指针
  DeferredRoutine 是此DPC对象绑定的回调函数,后面DeferredContext、SystemArgument1和SystemArgument2分别是此回调函数被调用时的参数。如ISR中调用IoRequestDpc时,后面两个参数就用于传递Irp和Context参数给DPC的回调函数。
  Lock 保存此DPC对象所在DPC队列的自旋锁,用于锁定DPC队列,同时也用于判断此DPC对象是否被加入到一个DPC队列中。

  了解了KDPC对象的结构,实际上维护代码就非常简单了。KeInitializeDpc函数将KDPC对象结构初始化为初值;IoInitializeDpcRequest函数则只是对KeInitializeDpc函数的一个简单包装,如下


以下为引用:

#define IoInitializeDpcRequest( DeviceObject, DpcRoutine ) (/
  KeInitializeDpc( &(DeviceObject)->Dpc,         /
           (PKDEFERRED_ROUTINE) (DpcRoutine),   /
           (DeviceObject) ) )




  注意WinXP/2003下实际上KeInitializeDpc函数和KeInitializeThreadedDpc函数都是由一个KiInitializeDpc函数完成具体工作的,只是传递的最后一个参数定义的对象类型不同。

<

 

 

 
说明
:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。
上一篇:利用钩子实现菜单阴影效果  下一篇:VC++的链接错误LNK2001