挂起当前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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值