IRP 续三 挂起当前IRP(转)

挂起当前IRP

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

 

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

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

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

这边是用户层的.

#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( &quot;线程开始进入等待状态!\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( &quot;打开设备失败!\n ); return -1; } //创建两个事件用于异步读取文件 StOverLapped1.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); StOverLapped2.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); //创建两个线程等待内核设置事件, 不然看不到效果 hThread[0] = CreateThread( NULL, 0, &amp;ThreadProc, &amp;StOverLapped1.hEvent, 0, &amp;dwThreadId[0] ); if ( hThread[0] == NULL ) { printf( &quot;创建线程1失败!\n ); return -1; } hThread[1] = CreateThread( NULL, 0, &amp;ThreadProc, &amp;StOverLapped2.hEvent, 0, &amp;dwThreadId[1] ); if ( hThread[1] == NULL ) { printf( &quot;创建线程2失败!\n ); } Sleep( 1000 ); //--------------------------------------------------------------------------- //向设备发送了两次写入请求, 都会被挂起. //--------------------------------------------------------------------------- RtlFillMemory( byBuf, sizeof( byBuf ), 'a'; ); bRet = WriteFile( hFile, byBuf, sizeof( byBuf ), &dwByteWrite, &StOverLapped1 ); if ( !bRet &amp;&amp; GetLastError() != ERROR_IO_PENDING ) { printf( "写入设备失败\n"; ); return -1; } RtlFillMemory( byBuf, sizeof( byBuf ), 'b' ); bRet = WriteFile( hFile, byBuf, sizeof( byBuf ), &dwByteWrite, &StOverLapped2 ); if ( !bRet &amp;&amp; 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( &quot;pause&quot; ); } return 0; }

这是内核代码

#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 &lt; 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 &lt; 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;
}

 

转载于:https://www.cnblogs.com/xmcc/archive/2012/04/12/2444674.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值