如果需要将IRP异步完成, 一般不会在处理函数中调用IoCompleteRequest函数, 因为调用IoCompleteRequest函数就意味着,该IRP请求处理完成了, 事实上很多时候是需要多次处理, 或者有其他需求的, 这边先谈谈将当前IRP挂起.
挂起意味着,是异步操作, 那么需要等待以后某个时机再处理, 当然这个时机问题的话, 以后会了解到, 目前需要解决的是挂起当前IRP的方法.
下面这个驱动的功能就是这样, 将所有的IRP都挂起, 在最后Win32这边调用CloseHandle的时候再统一处理, 完成那些IRP请求. 一种异步完成IRP的例子. 除了挂起还要取消什么的. 下一篇说.
主要说说这一篇的挂起操作. 挂起其实也很简单, 就是不调用IoCompleteRequest, 改为调用IoMarkIrpPending. 当然这些IRP需要自己用某种手段存放起来, 不然的话回头取就不知道怎么取出来了, 这边用的是系统提供的双向链表了. 调用IoMarkIrpPending以后返回STASTUS_PENDING那么, Win32调用函数这边就会返回ERROR_IO_PENDING, 当然这样并不代表有错误的, 只是IRP还没有完成而已..
这几天兴致不是很高啊, 上代码吧. 这边是用户层的.
008 | #pragma comment( linker, "/Entry:Jmain" ) |
010 | #define SYS_LINK_NAME "\\\\.\\SysLinkPendingIrp" |
014 | DWORD WINAPI ThreadProc( LPVOID lpParameter ) { |
017 | hEvent = *( HANDLE * )lpParameter; |
018 | printf ( "线程开始进入等待状态!\n" ); |
019 | WaitForSingleObject( hEvent, INFINITE ); |
026 | int __stdcall Jmain( int argc, char * argv[] ) { |
030 | HANDLE hThread[2] = {0}; |
033 | OVERLAPPED StOverLapped1 = {0}; |
034 | OVERLAPPED StOverLapped2 = {0}; |
038 | hFile = CreateFile( SYS_LINK_NAME, GENERIC_READ | GENERIC_WRITE, |
039 | 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0 ); |
041 | if ( hFile == INVALID_HANDLE_VALUE ) { |
042 | printf ( "打开设备失败!\n" ); |
047 | StOverLapped1.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); |
048 | StOverLapped2.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); |
051 | hThread[0] = CreateThread( NULL, 0, &ThreadProc, &StOverLapped1.hEvent, 0, &dwThreadId[0] ); |
053 | if ( hThread[0] == NULL ) { |
054 | printf ( "创建线程1失败!\n" ); |
058 | hThread[1] = CreateThread( NULL, 0, &ThreadProc, &StOverLapped2.hEvent, 0, &dwThreadId[1] ); |
059 | if ( hThread[1] == NULL ) { |
060 | printf ( "创建线程2失败!\n" ); |
067 | RtlFillMemory( byBuf, sizeof ( byBuf ), 'a' ); |
068 | bRet = WriteFile( hFile, byBuf, sizeof ( byBuf ), &dwByteWrite, &StOverLapped1 ); |
070 | if ( !bRet && GetLastError() != ERROR_IO_PENDING ) { |
071 | printf ( "写入设备失败\n" ); |
075 | RtlFillMemory( byBuf, sizeof ( byBuf ), 'b' ); |
076 | bRet = WriteFile( hFile, byBuf, sizeof ( byBuf ), &dwByteWrite, &StOverLapped2 ); |
078 | if ( !bRet && GetLastError() != ERROR_IO_PENDING ) { |
079 | printf ( "写入设备失败\n" ); |
084 | CloseHandle( hFile ); |
088 | WaitForMultipleObjects( 2, hThread, TRUE, INFINITE ); |
089 | printf ( "两个对象都已经返回!\n" ); |
093 | CloseHandle( hThread[0] ); |
097 | CloseHandle( hThread[1] ); |
100 | if ( StOverLapped1.hEvent ) { |
101 | CloseHandle( StOverLapped1.hEvent ); |
104 | if ( StOverLapped2.hEvent ) { |
105 | CloseHandle( StOverLapped2.hEvent ); |
109 | CloseHandle( hFile ); |
这边是内核态的代码:
007 | #define DEVICE_NAME L"\\Device\\DevPendingIrp" |
008 | #define SYS_LINK_NAME L"\\??\\SysLinkPendingIrp" |
011 | typedef struct tagDevice_Ext { |
012 | PDEVICE_OBJECT pDeviceObj; |
013 | PLIST_ENTRY pIrpListHead; |
014 | UNICODE_STRING USzDeviceName; |
015 | UNICODE_STRING USzSysLinkName; |
016 | } DEVICE_EXT, *PDEVICE_EXT; |
018 | typedef struct Irp_Entry { |
020 | LIST_ENTRY ListEntry; |
021 | } IRP_ENTRY, *PIRP_ENTRY; |
025 | #pragma code_seg( "PAGE" ) |
026 | VOID DriverUnLoad( PDRIVER_OBJECT pDriverObj ) { |
027 | PDEVICE_EXT pDeviceExt = NULL; |
028 | PDEVICE_OBJECT pNextDevice = NULL; |
031 | pNextDevice = pDriverObj->DeviceObject; |
033 | while ( pNextDevice != NULL ) { |
034 | pDeviceExt = pNextDevice->DeviceExtension; |
036 | IoDeleteDevice( pDeviceExt->pDeviceObj ); |
037 | IoDeleteSymbolicLink( &pDeviceExt->USzSysLinkName ); |
038 | KdPrint( ( "删除%wZ设备成功!\n" , &pDeviceExt->USzDeviceName ) ); |
040 | pNextDevice = pNextDevice->NextDevice; |
046 | NTSTATUS DispatchRoutine( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { |
050 | pIrp->IoStatus.Information = 0; |
051 | pIrp->IoStatus.Status = STATUS_SUCCESS; |
052 | IoCompleteRequest( pIrp, IO_NO_INCREMENT ); |
053 | return STATUS_SUCCESS; |
058 | NTSTATUS DispatchWrite( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { |
059 | PDEVICE_EXT pDeviceExt = NULL; |
060 | PIRP_ENTRY pIrpEntry = NULL; |
064 | pDeviceExt = pDeviceObj->DeviceExtension; |
065 | ASSERT( pDeviceExt != NULL ); |
067 | pIrpEntry = ( PIRP_ENTRY )ExAllocatePool( PagedPool, sizeof ( IRP_ENTRY ) ); |
068 | ASSERT ( pIrpEntry != NULL ); |
069 | pIrpEntry->pIRP = pIrp; |
072 | InsertHeadList( pDeviceExt->pIrpListHead, &pIrpEntry->ListEntry ); |
075 | IoMarkIrpPending( pIrp ); |
076 | KdPrint( ( "在IRP_MJ_WRITE请求中将IRP挂起!\n" ) ); |
078 | return STATUS_PENDING; |
083 | NTSTATUS Write_CompleteRequest( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { |
087 | PIO_STACK_LOCATION WriteStack = NULL; |
090 | WriteStack = IoGetCurrentIrpStackLocation( pIrp ); |
093 | ulWriteLength = WriteStack->Parameters.Write.Length; |
094 | ulWriteOffset = ( ULONG )WriteStack->Parameters.Write.ByteOffset.QuadPart; |
096 | for ( i = 0; i < ulWriteLength; i++ ) { |
097 | KdPrint( ( "%c\t" , *( ( ( UCHAR * )pIrp->AssociatedIrp.SystemBuffer ) + i ) ) ); |
103 | pIrp->IoStatus.Status = STATUS_SUCCESS; |
104 | pIrp->IoStatus.Information = ulWriteLength; |
105 | IoCompleteRequest( pIrp, IO_NO_INCREMENT ); |
106 | KdPrint( ( "写入请求处理完毕!\n" ) ); |
107 | return STATUS_SUCCESS; |
112 | NTSTATUS DispatchCleanUp( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { |
114 | PDEVICE_EXT pDeviceExt = NULL; |
115 | PIRP_ENTRY pIrpEntry = NULL; |
116 | PLIST_ENTRY pListEntry = NULL; |
119 | pDeviceExt = ( PDEVICE_EXT ) pDeviceObj->DeviceExtension; |
120 | Status = STATUS_UNSUCCESSFUL; |
122 | for ( ; !IsListEmpty( pDeviceExt->pIrpListHead ); pIrpEntry = NULL ) { |
124 | pListEntry = RemoveTailList( pDeviceExt->pIrpListHead ); |
127 | pIrpEntry = CONTAINING_RECORD( pListEntry, IRP_ENTRY, ListEntry ); |
130 | KdPrint( ( "获取结点数据失败!\n" ) ); |
131 | Status = STATUS_UNSUCCESSFUL; |
134 | Status = Write_CompleteRequest( pDeviceObj, pIrpEntry->pIRP ); |
136 | if ( !NT_SUCCESS( Status ) ) { |
137 | KdPrint( ( "完成写入请求时失败!\n" ) ); |
140 | ExFreePool( pIrpEntry ); |
142 | KdPrint( ( "未决请求处理完成!\n" ) ); |
147 | pIrp->IoStatus.Status = Status; |
148 | pIrp->IoStatus.Information = 0; |
149 | IoCompleteRequest( pIrp, IO_NO_INCREMENT ); |
155 | #pragma code_seg( "INIT" ) |
156 | NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) { |
159 | PDEVICE_OBJECT pDevice = NULL; |
160 | PDEVICE_EXT pDeviceExt = NULL; |
161 | UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( DEVICE_NAME ); |
162 | UNICODE_STRING UszSysLink = RTL_CONSTANT_STRING( SYS_LINK_NAME ); |
164 | Status = IoCreateDevice( pDriverObj, sizeof ( DEVICE_EXT ), &USzDeviceName, |
165 | FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevice ); |
167 | if ( !NT_SUCCESS( Status ) ) { |
168 | KdPrint( ( "创建设备失败!\n" ) ); |
172 | Status = IoCreateSymbolicLink( &UszSysLink, &USzDeviceName ); |
174 | if ( !NT_SUCCESS( Status ) ) { |
175 | IoDeleteDevice( pDevice ); |
176 | KdPrint( ( "创建符号链接失败!\n" ) ); |
181 | pDevice->Flags |= DO_BUFFERED_IO; |
182 | pDeviceExt = pDevice->DeviceExtension; |
183 | pDeviceExt->pDeviceObj = pDevice; |
184 | pDeviceExt->USzDeviceName = USzDeviceName; |
185 | pDeviceExt->USzSysLinkName = UszSysLink; |
188 | pDeviceExt->pIrpListHead = ( PLIST_ENTRY )ExAllocatePool( PagedPool, sizeof ( LIST_ENTRY ) ); |
189 | InitializeListHead( pDeviceExt->pIrpListHead ); |
192 | for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) { |
193 | pDriverObj->MajorFunction[i] = &DispatchRoutine; |
196 | pDriverObj->DriverUnload = &DriverUnLoad; |
197 | pDriverObj->MajorFunction[IRP_MJ_WRITE] = &DispatchWrite; |
198 | pDriverObj->MajorFunction[IRP_MJ_CLEANUP] = &DispatchCleanUp; |