挂起当前IRP

如果需要将IRP异步完成, 一般不会在处理函数中调用IoCompleteRequest函数, 因为调用IoCompleteRequest函数就意味着,该IRP请求处理完成了, 事实上很多时候是需要多次处理, 或者有其他需求的, 这边先谈谈将当前IRP挂起.

挂起意味着,是异步操作, 那么需要等待以后某个时机再处理, 当然这个时机问题的话, 以后会了解到, 目前需要解决的是挂起当前IRP的方法.

下面这个驱动的功能就是这样, 将所有的IRP都挂起, 在最后Win32这边调用CloseHandle的时候再统一处理, 完成那些IRP请求. 一种异步完成IRP的例子. 除了挂起还要取消什么的. 下一篇说.

主要说说这一篇的挂起操作. 挂起其实也很简单, 就是不调用IoCompleteRequest, 改为调用IoMarkIrpPending. 当然这些IRP需要自己用某种手段存放起来, 不然的话回头取就不知道怎么取出来了, 这边用的是系统提供的双向链表了. 调用IoMarkIrpPending以后返回STASTUS_PENDING那么, Win32调用函数这边就会返回ERROR_IO_PENDING, 当然这样并不代表有错误的, 只是IRP还没有完成而已..

这几天兴致不是很高啊, 上代码吧. 这边是用户层的.

/*
	Windows内核下挂起当前IRP, 在IRP_MJ_CLEANUP中统一完成 3环代码
	编译方法参见makefile. TAB = 8
*/
#include <stdio.h>
#include <windows.h>

#pragma comment( linker, "/Entry:Jmain" )

#define SYS_LINK_NAME	"\\\\.\\SysLinkPendingIrp"
//===========================================================================
//线程等待函数
//===========================================================================
DWORD WINAPI ThreadProc( LPVOID lpParameter ) {
	HANDLE hEvent;

	hEvent = *( HANDLE* )lpParameter;
	printf( "线程开始进入等待状态!\n" );
	WaitForSingleObject( hEvent, INFINITE );
	ExitThread( 0 );
}

//===========================================================================
//用户层的启动函数
//===========================================================================
int __stdcall Jmain( int argc, char* argv[] ) {
	HANDLE	hFile = 0;
	BOOL	bRet;
	DWORD	dwByteWrite;
	HANDLE	hThread[2] = {0};
	DWORD	dwThreadId[2];
	BYTE	byBuf[10];
	OVERLAPPED StOverLapped1 = {0};
	OVERLAPPED StOverLapped2 = {0};

	__try {
		//异步打开设备. 下面操作的函数都是异步的
		hFile = CreateFile( SYS_LINK_NAME, GENERIC_READ | GENERIC_WRITE,
		                    0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0 );

		if ( hFile == INVALID_HANDLE_VALUE ) {
			printf( "打开设备失败!\n" );
			return -1;
		}

		//创建两个事件用于异步读取文件
		StOverLapped1.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
		StOverLapped2.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );

		//创建两个线程等待内核设置事件, 不然看不到效果
		hThread[0] = CreateThread( NULL, 0, &ThreadProc, &StOverLapped1.hEvent, 0, &dwThreadId[0]  );

		if ( hThread[0] == NULL ) {
			printf( "创建线程1失败!\n" );
			return -1;
		}

		hThread[1] = CreateThread( NULL, 0, &ThreadProc, &StOverLapped2.hEvent, 0, &dwThreadId[1]  );
		if ( hThread[1] == NULL ) {
			printf( "创建线程2失败!\n" );
		}

		Sleep( 1000 );
//---------------------------------------------------------------------------
		//向设备发送了两次写入请求, 都会被挂起.
//---------------------------------------------------------------------------
		RtlFillMemory( byBuf, sizeof( byBuf ), 'a' );
		bRet =  WriteFile( hFile, byBuf, sizeof( byBuf ), &dwByteWrite, &StOverLapped1 );

		if ( !bRet && GetLastError() != ERROR_IO_PENDING ) {
			printf( "写入设备失败\n" );
			return -1;
		}

		RtlFillMemory( byBuf, sizeof( byBuf ), 'b' );
		bRet =  WriteFile( hFile, byBuf, sizeof( byBuf ), &dwByteWrite, &StOverLapped2 );

		if ( !bRet && GetLastError() != ERROR_IO_PENDING ) {
			printf( "写入设备失败\n" );
			return -1;
		}

		if ( hFile ) {
			CloseHandle( hFile );
		}

		//等待多个对象返回(必须同时返回)
		WaitForMultipleObjects( 2, hThread, TRUE, INFINITE );
		printf( "两个对象都已经返回!\n" );
//---------------------------------------------------------------------------
	} __finally {
		if ( hThread[0] ) {
			CloseHandle( hThread[0] );
		}

		if ( hThread[1] ) {
			CloseHandle( hThread[1] );
		}

		if ( StOverLapped1.hEvent ) {
			CloseHandle( StOverLapped1.hEvent );
		}

		if ( StOverLapped2.hEvent ) {
			CloseHandle( StOverLapped2.hEvent );
		}

		if ( hFile ) {
			CloseHandle( hFile );
		}
		system( "pause" );
	}

	return 0;
}

这边是内核态的代码:

/*
	Windows内核下挂起当前IRP, 在IRP_MJ_CLEANUP中统一完成 0环代码
	编译方法参见makefile. TAB = 8
*/
#include <ntddk.h>

#define DEVICE_NAME	L"\\Device\\DevPendingIrp"
#define SYS_LINK_NAME	L"\\??\\SysLinkPendingIrp"

//---------------------------------------------------------------------------
typedef struct tagDevice_Ext {
	PDEVICE_OBJECT	pDeviceObj;
	PLIST_ENTRY	pIrpListHead;	//链表头结点, 用于存放IRP请求
	UNICODE_STRING	USzDeviceName;
	UNICODE_STRING	USzSysLinkName;
} DEVICE_EXT, *PDEVICE_EXT;

typedef struct Irp_Entry {
	PIRP pIRP;
	LIST_ENTRY ListEntry;
} IRP_ENTRY, *PIRP_ENTRY;
//===========================================================================
//驱动卸载例程
//===========================================================================
#pragma  code_seg( "PAGE" )
VOID	DriverUnLoad( PDRIVER_OBJECT pDriverObj ) {
	PDEVICE_EXT pDeviceExt = NULL;
	PDEVICE_OBJECT pNextDevice = NULL;

	PAGED_CODE();
	pNextDevice = pDriverObj->DeviceObject;

	while ( pNextDevice != NULL ) {
		pDeviceExt = pNextDevice->DeviceExtension;

		IoDeleteDevice( pDeviceExt->pDeviceObj );
		IoDeleteSymbolicLink( &pDeviceExt->USzSysLinkName );
		KdPrint( ( "删除%wZ设备成功!\n", &pDeviceExt->USzDeviceName ) );

		pNextDevice = pNextDevice->NextDevice;
	}
}
//===========================================================================
//所有不关心的IRP处理例程
//===========================================================================
NTSTATUS DispatchRoutine( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {

	PAGED_CODE();

	pIrp->IoStatus.Information = 0;
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	return STATUS_SUCCESS;
}
//===========================================================================
//IRP_MJ_WRITE的处理, 将所有的IRP都返回为pending状态
//===========================================================================
NTSTATUS DispatchWrite( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	PDEVICE_EXT pDeviceExt = NULL;
	PIRP_ENTRY pIrpEntry = NULL;

	PAGED_CODE();

	pDeviceExt = pDeviceObj->DeviceExtension;
	ASSERT( pDeviceExt != NULL );

	pIrpEntry = ( PIRP_ENTRY )ExAllocatePool( PagedPool, sizeof( IRP_ENTRY ) );
	ASSERT ( pIrpEntry != NULL );
	pIrpEntry->pIRP = pIrp;

	//插入队列
	InsertHeadList( pDeviceExt->pIrpListHead, &pIrpEntry->ListEntry );

	//将IRP设置为挂起
	IoMarkIrpPending( pIrp );
	KdPrint( ( "在IRP_MJ_WRITE请求中将IRP挂起!\n" ) );
	//返回pending状态
	return STATUS_PENDING;
}
//===========================================================================
//将未决的写入请求完成
//===========================================================================
NTSTATUS Write_CompleteRequest( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	ULONG i;
	ULONG ulWriteLength;
	ULONG ulWriteOffset;
	PIO_STACK_LOCATION WriteStack = NULL;

	PAGED_CODE();
	WriteStack = IoGetCurrentIrpStackLocation( pIrp );

	//欲写入的长度, 偏移
	ulWriteLength = WriteStack->Parameters.Write.Length;
	ulWriteOffset = ( ULONG )WriteStack->Parameters.Write.ByteOffset.QuadPart;

	for( i = 0; i < ulWriteLength; i++ ) {
		KdPrint( ( "%c\t", *( ( ( UCHAR* )pIrp->AssociatedIrp.SystemBuffer ) + i ) ) );
	}

	KdPrint( ( "\n" ) );

	//简单的完成IRP请求
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	pIrp->IoStatus.Information = ulWriteLength;
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	KdPrint( ( "写入请求处理完毕!\n" ) );
	return STATUS_SUCCESS;
}
//===========================================================================
//IRP_MJ_CLEANUP IRP的处理, 将IRP_MJ_WRITE未决的IRP全部处理下
//===========================================================================
NTSTATUS DispatchCleanUp( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
	NTSTATUS	Status;
	PDEVICE_EXT	pDeviceExt = NULL;
	PIRP_ENTRY	pIrpEntry = NULL;
	PLIST_ENTRY	pListEntry = NULL;

	PAGED_CODE();
	pDeviceExt = ( PDEVICE_EXT ) pDeviceObj->DeviceExtension;
	Status = STATUS_UNSUCCESSFUL;

	for( ; !IsListEmpty( pDeviceExt->pIrpListHead ); pIrpEntry = NULL ) {

		pListEntry = RemoveTailList( pDeviceExt->pIrpListHead );

		//获取IRP的数据指针
		pIrpEntry = CONTAINING_RECORD( pListEntry, IRP_ENTRY, ListEntry );

		if ( !pIrpEntry ) {
			KdPrint( ( "获取结点数据失败!\n" ) );
			Status = STATUS_UNSUCCESSFUL;
		} else {
			//完成写入请求
			Status = Write_CompleteRequest( pDeviceObj, pIrpEntry->pIRP );

			if ( !NT_SUCCESS( Status ) ) {
				KdPrint( ( "完成写入请求时失败!\n" ) );
			}

			ExFreePool( pIrpEntry );

			KdPrint( ( "未决请求处理完成!\n" ) );
		}
	}

	//处理IRP_MJ_CLEANUP自身的IRP请求
	pIrp->IoStatus.Status = Status;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	return Status;
}
//===========================================================================
//驱动程序的入口函数
//===========================================================================
#pragma code_seg( "INIT" )
NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) {
	ULONG i;
	NTSTATUS Status;
	PDEVICE_OBJECT pDevice = NULL;
	PDEVICE_EXT pDeviceExt = NULL;
	UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( DEVICE_NAME );
	UNICODE_STRING UszSysLink = RTL_CONSTANT_STRING( SYS_LINK_NAME );

	Status = IoCreateDevice( pDriverObj, sizeof( DEVICE_EXT ), &USzDeviceName,
	                         FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevice );

	if ( !NT_SUCCESS( Status ) ) {
		KdPrint( ( "创建设备失败!\n" ) );
		return Status;
	}

	Status = IoCreateSymbolicLink( &UszSysLink, &USzDeviceName );

	if ( !NT_SUCCESS( Status ) ) {
		IoDeleteDevice( pDevice );
		KdPrint( ( "创建符号链接失败!\n" ) );
		return Status;
	}

	//带缓冲区的IO方式
	pDevice->Flags |= DO_BUFFERED_IO;
	pDeviceExt = pDevice->DeviceExtension;
	pDeviceExt->pDeviceObj = pDevice;
	pDeviceExt->USzDeviceName = USzDeviceName;
	pDeviceExt->USzSysLinkName = UszSysLink;

	//初始化链表头结点
	pDeviceExt->pIrpListHead = ( PLIST_ENTRY )ExAllocatePool( PagedPool, sizeof( LIST_ENTRY ) );
	InitializeListHead( pDeviceExt->pIrpListHead );

	//设置分发函数, 驱动卸载函数
	for( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) {
		pDriverObj->MajorFunction[i] = &DispatchRoutine;
	}

	pDriverObj->DriverUnload = &DriverUnLoad;
	pDriverObj->MajorFunction[IRP_MJ_WRITE] = &DispatchWrite;
	pDriverObj->MajorFunction[IRP_MJ_CLEANUP] = &DispatchCleanUp;

	return Status;
}

 

网友评论:

  1. Isabella 说:

    You’ve really imspesred me with that answer!

  2. http://inetdome.us/diply.com 说:

    House.Each Bargello box is worked in three tones of one color. The lightest tone is worked in the Bargello Brick Filler Stitch in a 4-2 step of the front face of each box; the medium and dark tones are worked in a Gobelin

发表评论


Verify Code   If you cannot see the CheckCode image,please refresh the page again!