<学习笔记>Windows驱动开发技术详解__IRP的同步

本文详细介绍了Windows驱动中IRP(I/O请求包)的同步处理,包括同步和异步操作的原理、同步与异步操作设备的方法,以及IRP的同步完成、异步完成、StartIO例程和中断服务例程在IRP同步中的作用。重点讨论了如何利用StartIO和中断服务例程实现设备操作的串行化,确保正确处理并行IRP请求。
摘要由CSDN通过智能技术生成

对设备的任何操作都会最终转化为IRP请求,而IRP一般都是由操作系统异步发送的。异步处理IRP有助于提高效率,但是有时异步处理会带来逻辑上的错误,这时需要将异步的IRP同步化。将IRP同步化的方法有StartIO例程,使用中断服务例程等。


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

大部分IRP都是由应用程序的Win32 API函数发起的。这些Win32 API本身就支持同步和异步的操作。例如:ReadFile,WriteFile和DeviceIoControl等,这些都有两种操作方式。一种同步,一种异步。


1.同步操作和异步操作的原理

操作设备的Win32 API主要是三个函数,即ReadFile函数,WriteFile函数,DeviceIOControl函数。以DeviceIOControl函数为例,当应用程序调用DeviceIoControl函数时,它的内部会创建一个IRP_MJ_DEVICE_CONTROL类型的IRP,并将这个IRP传送到驱动程序的派遣函数中。处理该IRP需要一段时间,直到IRP处理完毕后,DeviceIOControl函数才会返回。

同步操作时,在DeviceIOControl的内部,会调用WaitForSingleObject函数去等待一个事件。这个事件直到IRP被结束时,才会被触发。如果通过反汇编IoCompleteRequest内核函数,就会发现IoComplpeteRequest内部设置了该事件。DeviceIOControl会暂时进入睡眠状态,直到IRP被结束。

而对于异步操作的情况下,当DeviceIOControl被调用时,其内部会产生IRP,并将IRP传递给驱动程序的内部派遣函数。但此时DeviceIOControl不会等待该IRP的结束,而是直接返回。当IRP经过一段时间被结束时,操作系统会触发一个IRP相关事件。这个事件可以通知应用程序IRP请求被执行完毕。


2.同步操作设备

如果需要同步操作设备,在打开设备的时候就要制定以“同步”的方式打开设备。打开设备用CreateFile函数,其函数声明如下:

HANDLE
  CreateFile(
                LPCSTR lpFileName,                                  //设备名
		DWORD dwDesiredAccess,                              //访问权限
		DWORD dwShareMode,                                  //共享模式
		LPSECURITY_ATTRIBUTES lpSecurityAttributes,         //安全属性
		DWORD dwCreationDisposition,                        //如何创建
		DWORD dwFlagsAndAttributes,                         //设备属性
		HANDLE hTemplateFile                                //文件模板
	);

其中第六个参数dwFlagsAndAttributes是同步异步操作的关键。如果这个参数没有设置FILE_FLAG_OVERLAPPED,则以后对该设备的操作都是同步操作,否则都是异步操作。

对设备的操作Win32 API,例如ReadFile,WriteFile和DeviceIOControl函数,都会提供一个OVERLAP参数,如ReadFile函数:

BOOL ReadFile(
	HANDLE hFile,
	LPVOID lpBuffer,
	DWORD nNumberOfBytesToRead, 
	LPDWORD lpNumberOfBytesRead,
	LPOVERLAPPED lpOverlapped 
);

在同步操作设备时,其lpOverlapped参数设置为NULL。下面代码演示了应用程序如何对设备进行同步读取:

#include <windows.h>
#include <stdio.h>

#define BUFFER_SIZE	512
int main()
{
	HANDLE hDevice = 
		CreateFile("test.dat",
					GENERIC_READ | GENERIC_WRITE,
					0,
					NULL,
					OPEN_EXISTING,
					FILE_ATTRIBUTE_NORMAL,//此处没有设置FILE_FLAG_OVERLAPPED
					NULL );

	if (hDevice == INVALID_HANDLE_VALUE) 
	{
		printf("Read Error\n");
		return 1;
	}

	UCHAR buffer[BUFFER_SIZE];
	DWORD dwRead;
	ReadFile(hDevice,buffer,BUFFER_SIZE,&dwRead,NULL);//这里没有设置OVERLAP参数

	CloseHandle(hDevice);

	return 0;
}


3.异步操作设备(方式一)

异步操作设备时主要需要OVERLAP参数,Windows中用一种数据结构OVERLAPPED表示。

typedef struct _OVERLAPPED
{
	ULONG_PTR Internal;
	ULONG_PTR InternalHigh;
	DWORD Offset;
	DWORD OffsetHigh;
	HANDLE hEvent;
}OVERLAPPED;

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

第四个参数OffsetHigh是偏移量的高32位。

第五个参数hEvent:这个事件用于该操作完成后通知应用程序。程序员可以初始化该事件为未激发,当操作设备结束后,即在驱动程序中调用IoCompleteRequest后,设置该事件为激发态。

在使用OVERLAPPED结构前,要先对其内部清零,并为其创建事件。

下面代码演示如何在应用程序中使用异步操作:

#include <windows.h>
#include <stdio.h>

#define BUFFER_SIZE	512
//假设该文件大于或等于BUFFER_SIZE

#define DEVICE_NAME	"test.dat"
int main()
{
	HANDLE hDevice = 
		CreateFile("test.dat",
					GENERIC_READ | GENERIC_WRITE,
					0,
					NULL,
					OPEN_EXISTING,
					FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,//此处设置FILE_FLAG_OVERLAPPED
					NULL );

	if (hDevice == INVALID_HANDLE_VALUE) 
	{
		printf(&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值