文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>27、Windows内核编程,IRP的同步(1)

27、Windows内核编程,IRP的同步(1)

时间:2010-11-08  来源:edwardlewiswe

对设备的任何操作都会转化为IRP请求,而IRP一般都是由操作系统异步发送的。但是有时需要同步来避免逻辑错误。同步方法有:StartIO例程,使用中断服务例程等。

1、应用程序对设备的同步异步操作

1)同步操作原理

大部分IRP是由应用程序的Win32 API发起。这些函数本身就支持同步异步操作。如ReadFile,WriteFile,DeviceIoControl等。

图示 IRP同步操作示意图P250

2)同步操作设备

如CreateFile,其参数dwFlagsAndAttributes 是同步异步的关键。没有设置FILE_FLAG_OVERLAPPED为同步,否则为异步。

再如ReadFile,其参数lpOverlapped 如果设为NULL,则为同步。

示例代码 P252

3)异步操作设备

法一:通过OVERLAPPED 结构体。

typedef struct _OVERLAPPED {

ULONG_PTR Internal;

ULONG_PTR InternalHigh;

DWORD Offset;

DWORD OffsetHigh;

HANDLE hEvent;

} OVERLAPPED;

第三个参数:操作设备会指定一个偏移量,从设备的偏移量进行读取。该偏移量用一个64位整形表示。Offset为该偏移量的低32位整形,OffsetHigh为高32位整形。

hEvent用于操作完成后通知应用程序。我们可以初始化其为未激发状态,当操作设备结束后,即在驱动中调用IoCompleteRequest后,设备该事件激发态。

OVERLAPPED 结构使用前要清0,并为其创建事件。

示例代码 P254

法二:ReadFileEx与WriteFileEx 专门被用来异步操作。

BOOL WriteFileEx(

HANDLE hFile, // handle to output file

LPCVOID lpBuffer, // data buffer

DWORD nNumberOfBytesToWrite, // number of bytes to write

LPOVERLAPPED lpOverlapped, // overlapped buffer

LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine // completion routine

);

lpOverlapped不需要提供事件句柄。

ReadFileEx 将读请求传递到驱动程序后立即返回。驱动程序在结束读操作后,会通过调用ReadFileEx提供的回调函数(Call Back Function)lpCompletionRoutine 。类似于一个软中断。Windows将这种机制称为异步过程调用APC(asynchronous procedure call )。只有线程于Alert状态时,回调函数才能被调用。多个函数使系统进行Alert状态:SleepEx,WaitForMultipleObjectsEx,WaitForSingleObjectEx,etc。

OS一旦结束读取操作,就会把相应的completion routine插入到APC队列中。当OS进入Alert状态后,会枚举当前线程的APC队列。

示例代码 P255

2、IRP的同步完成和异步完成

两种方法,一种是在派遣函数中直接结束IRP,称为同步方法。另外一种是在派遣函数中不结束IRP,而让派遣函数直接返回,IRP在以后某个时候再进行处理,也称为异步方法。

比如在ReadFile中同步时,派遣函数在调用IoCompleteRequest时,IoCompleteRequest内部会设置IRP的UserEvent事件。

如果在ReadFile异步时,ReadFile不创建事件,但是接收overlap参数,IoCompleteRequest内部会设置overlap提供的事件。

在ReadFileEx异步中,IoCompleteRequest将ReadFileEx提供的回调函数插入到APC队列中。

异步时,通过GetLastError()得到ERROR_IO_INCOMPLETE。如果派遣函数不调用IoCompleteRequest,此时IRP处于挂起状态。处理方法见示例代码中。

同时,应用程序关闭设置时产生IRP_MJ_CLEANUP类型的IRP。可以在IRP_MJ_CLEANUP的派遣函数中调用IoCompleteRequest来结束那些挂起的IRP请求。

示例代码 P260

取消IRP

PDRIVER_CANCEL

  IoSetCancelRoutine(

    IN PIRP  Irp,

    IN PDRIVER_CANCEL  CancelRoutine

    );

来设置取消IRP请求的回调函数。也可以用来删除取消例程,当CancelRoutine为空指针时,则删除原来设置的取消例程。

       用IoCancelIrp函数指定取消IRP请求。在IoCancelIrp内部,通过cancel lock来进行同步。

IoReleaseCancelSpinLock

IoAcquireCancelSpinLock

       可以用CancelIo API 来取消IRP请求。在CancelIo内部会枚举所有没有被完成的IRP,依次调用IoCancelIrp。如果应用程序没有调用CancelIo,在应用程序关闭时也会自动调用CancelIo。

       注意:cancel lock是全局自旋锁,占用时间不宜太长。

示例代码 P264

 

 

 

相关阅读 更多 +
排行榜 更多 +
云漫

云漫

生活实用 下载
证照签

证照签

生活实用 下载
云漫文学

云漫文学

生活实用 下载