大部分的IRP都源于文件I/O处理Win32 API,如CreateFile、ReadFile等。处理这些IRP最简单的就是是在相应的派造函数中,将IRP的状态设置为成功,然后结束IRP的请求,并让派遣函数返回成功。结束IRP的请求使用函数IoCompleteRequest。下面的代码演示了一种最简单的处理IRP请求的派遣函数。
NTSTATUS HelloDDKDispatchRouthin(IN PDEVICE_OBJECT pDevoBJ, IN PIRP pIrp)
{
KdPrint(("Enter HelloDDKDispatchRouthin!\n"));
// 对一般IRP的简单操作,后面会介绍对IRP更复杂的操作
NTSTATUS status = STATUS_SUCCESS;
// 设置IRP完成状态
pIrp->IoStatus.Information = 0;
// 处理IRP
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
KdPrint(("Leave HelloDDKDispatchRouthin!\n"));
return status;
}
在本例中,派遣函数设置了IRP的完成状态为STATUS_SUCCESS。这样,发起I/O请求的Win32 API(如 WriteFile)将会返回 TRUE。相反,如果将IRP的完成状态设置为不成功,这时发起I/O请求的Win32 API(如 WriteFile)将会返回 FALSE。这种情况时,可以使用GetLastErmor Win32 API得到错误代码。所得的错误代码会和 IRP 设置的状态相一致。
除了设置IRP的完成状态,派遣函数还要设置这个IRP请求操作了多少字节。在本例中,将操作字节数简单地设置成了0。如果是ReadFile产生的IRP,这个字节数代表从设备读了多少字节。如果是WriteFile产生的IRP,这个字节数代表对设备写了多少字节。最后,派遣函数将 IRP 请求结束,这是通过 IoCompleteRequest函数完成的,loCompleteRequest的声明如下:
VOID IoCompleteRequest(
IN PIRP Irp,
IN CCHAR PriorityBoost
);
// Irp:代表需要被结束的IRP。
// PriorityBoost:代表线程恢复时的优先级别。
为了解释优先级的概念,需要了解一下与文件I/O相关的 Win32 API的内部操作过程。
这里以ReadFile为例,ReadFile 的内部操作大体是这样的:
a. ReadFile 调用 ntdll 中的 NtReadFile。 其中 ReadFile 函数是 Win32 API,
而 NtReadFile函数是 Native API。
b. ntdll中的 NtReadFile 进入到内核模式,并调用系统服务中的 NtReadFile 函数。
c. 系统服务函数 NReadFile 创建 IRP_MJ_WRITE 类型的IRP,
然后它将这个IRP发送到某个驱动程序的派遭函数中。NtReadFile 然后去等待一个事件,
这时当前线程进入“睡眼”,状态,也可以说当前线程被阻塞住或者线程处于“pending”状态。
d. 在派遣函数中一般会将IRP 请求结束,结束IRP是通过IoCompleteRequest函数,
在IoCompleteRequest函数内部会设置刚才等待的事件,“睡眠”的线程被恢复运行。
例如,在读一个很大的文件(或者设备)时,ReadFile不会立刻返回,而是等待一段时间。这段时间就是当前线程“睡眠”的那段时间。IRP请求被结束,标志这个操作执行完毕,这时“睡眠”的线程被唤醒。
IocompleteReguct函数中第二个参数PriorityBoost代表一种优先级,指的是被阻塞的线程以何种优先级恢复运行。一般情况下,优先级设置为IO_NO_INCREMENT。对某些特殊情况,需要将阻塞的线程以“优先”的身份恢复运行。如键盘、鼠标等输入设备,它们需要更快地反应。
优先级 | 说明 |
IO_NO_INCREMENT | 不增加优先级 |
IO_CD_ROM_INCREMENT | 光驱设备增加的优先级 |
IO_DISK_INCREMENT | 磁盘设备增加的优先级 |
IO_KEYBOARD_INCREMENT | 键盘设备增加的优先级 |
IO_MOUSE_INCREMENT | 鼠标设备增加的优先级 |
IO_NAMED_PIPE_INCREMENT | 命名管道增加的优先级 |
IO_NETWORK_INCREMENT | 网络设备增加的优先级 |
IO_PARALLEL_INCREMENT | 并口设备增加的优先级 |
IO_SERIAL_INCREMENT | 串口设备增加的优先级 |
IO_SOUND_INCREMENT | 声卡设备增加的优先级 |
IO_VIDEO_INCREMENT | 视频设备增加的优先级 |
SEMAPHORE_JNCREMENT | 信号灯增加的优先级 |
本节只讨论了派遣函数中最简单的处理IRP的方法,在实际应用中往往要比这个复杂的多。