vennychang
驱动牛犊
驱动牛犊
  • 注册日期2003-02-07
  • 最后登录2005-03-01
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1411回复:4

急救 取消Irp 太久了!!!

楼主#
更多 发布于:2004-07-20 15:47
取消一个正在control pipe上等待资料的irp,使用IoCancelIrp()需要多久的时间才能让它中断工作呢?
在自已的测试中发现竟然要高达数百ms,
这个结果让我的传输工作大打折扣,请问有没有人碰过类似的情况,如何处理?
punk
驱动小牛
驱动小牛
  • 注册日期2001-04-07
  • 最后登录2018-06-01
  • 粉丝0
  • 关注0
  • 积分621分
  • 威望164点
  • 贡献值0点
  • 好评度60点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2004-07-21 08:42
取消一个正在control pipe上等待资料的irp,使用IoCancelIrp()需要多久的时间才能让它中断工作呢?
在自已的测试中发现竟然要高达数百ms,
这个结果让我的传输工作大打折扣,请问有没有人碰过类似的情况,如何处理?
 

恐怕要看lower device是怎么管理irp队列的
不停学习
wowocock
VIP专家组
VIP专家组
  • 注册日期2002-04-08
  • 最后登录2016-01-09
  • 粉丝16
  • 关注2
  • 积分601分
  • 威望1651点
  • 贡献值1点
  • 好评度1227点
  • 原创分1分
  • 专家分0分
板凳#
发布于:2004-07-21 08:57
有些事不是你能管的了的......
花开了,然后又会凋零,星星是璀璨的,可那光芒也会消失。在这样 一瞬间,人降生了,笑者,哭着,战斗,伤害,喜悦,悲伤憎恶,爱。一切都只是刹那间的邂逅,而最后都要归入死亡的永眠
tianrongcai
驱动牛犊
驱动牛犊
  • 注册日期2005-06-24
  • 最后登录2011-03-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望39点
  • 贡献值0点
  • 好评度17点
  • 原创分0分
  • 专家分0分
地板#
发布于:2005-07-26 16:13
WDM IRP-Handling Tips

To retain ownership of an IRP in an IRP handler function, return STATUS_PENDING.
To retain ownership of an IRP in a completion routine, return STATUS_MORE_PROCESSING_REQUIRED.
If you free the IRP in your completion routine, also return STATUS_MORE_PROCESSING_REQUIRED.
If you queue an IRP (whether completed or not), you must set a cancel routine.
Right after setting a cancel routine, check that the IRP was not already cancelled.
Your cancel routine must call IoReleaseCancelSpinLock to release the global cancel spinlock whether or not the cancel routine actually completes any IRPs. Do this after acquiring your local spinlock and before calling outside the driver to complete the cancelled IRP.
Only the cancel routine needs to release the cancel spinlock. If you discover that the IRP was cancelled as you're about to queue it, and you never set the cancel routine, then IoCancelIrp releases the cancel spinlock for you. IoCancelIrp either calls a cancel routine or releases the cancel spinlock itself, not both.
When dequeuing an IRP, Irp->Cancel TRUE indicates that the IRP was cancelled. It does not indicate whether your cancel routine was called. The way to determine that is to test and clear the cancel routine using IoSetCancelRoutine(Irp, NULL). If the result is NULL, the cancel routine was called; otherwise, it was not called.
Whenever you are about to return STATUS_PENDING for an IRP, call the IoMarkIrpPending macro on that IRP. Do this while still holding the local spinlock.
If you reuse an IRP, make sure to first call IoInitializeIrp, which clears the Cancel field.
Never call outside your driver while holding a spinlock.
Functions that execute only at IRQL<DISPATCH_ LEVEL can be made pageable. However, if any part of the function executes while holding a spinlock, that code will execute at a higher IRQL, so the code and any data that it touches must be locked.
For unsupported IRPs, your dispatch function should either pass the IRP down to the next driver or complete it without changing the default status.
tianrongcai
驱动牛犊
驱动牛犊
  • 注册日期2005-06-24
  • 最后登录2011-03-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望39点
  • 贡献值0点
  • 好评度17点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2005-07-26 16:57
//
// An IRPLOCK allows for safe cancellation. The idea is to protect the IRP
// while the canceller is calling IoCancelIrp. This is done by wrapping the
// call in InterlockedExchange(s). The roles are as follows:
//
// Initiator/completion: Cancelable --> IoCallDriver() --> Completed
// Canceller: CancelStarted --> IoCancelIrp() --> CancelCompleted
//
// No cancellation:
//   Cancelable-->Completed
//
// Cancellation, IoCancelIrp returns before completion:
//   Cancelable --> CancelStarted --> CancelCompleted --> Completed
//
// Canceled after completion:
//   Cancelable --> Completed -> CancelStarted
//
// Cancellation, IRP completed during call to IoCancelIrp():
//   Cancelable --> CancelStarted -> Completed --> CancelCompleted
//
//  The transition from CancelStarted to Completed tells the completer to block
//  postprocessing (IRP ownership is transferred to the canceller). Similarly,
//  the canceller learns it owns IRP postprocessing (free, completion, etc)
//  during a Completed->CancelCompleted transition.
//


NTSTATUS
MakeSynchronousIoctlWithTimeOut(
    IN PDEVICE_OBJECT    TopOfDeviceStack,
    IN ULONG         IoctlControlCode,
    PVOID             InputBuffer,
    ULONG             InputBufferLength,
    PVOID             OutputBuffer,
    ULONG             OutputBufferLength,
    IN  ULONG               Milliseconds
    )
/*++

Arguments:

    TopOfDeviceStack   -

    IoctlControlCode   - Value of the IOCTL request.

    InputBuffer        - Buffer to be sent to the TopOfDeviceStack.

    InputBufferLength  - Size of buffer to be sent to the TopOfDeviceStack.

    OutputBuffer       - Buffer for received data from the TopOfDeviceStack.

    OutputBufferLength - Size of receive buffer from the TopOfDeviceStack.

    Milliseconds       - Timeout value in Milliseconds

Return Value:

    NT status code

--*/
{
    NTSTATUS status;
    PIRP irp;
    KEVENT event;
    IO_STATUS_BLOCK ioStatus;
    LARGE_INTEGER dueTime;
    IRPLOCK lock;

    KeInitializeEvent(&event, NotificationEvent, FALSE);

    irp = IoBuildDeviceIoControlRequest (
                    IoctlControlCode,
                    TopOfDeviceStack,
                    InputBuffer,
                    InputBufferLength,
                    OutputBuffer,
                    OutputBufferLength,
                    FALSE, // External ioctl
                    &event,
                    &ioStatus);



    if (irp == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    lock = IRPLOCK_CANCELABLE;

    IoSetCompletionRoutine(
                    irp,
                    MakeSynchronousIoctlWithTimeOutCompletion,
                    &lock,
                    TRUE,
                    TRUE,
                    TRUE
                    );

    status = IoCallDriver(TopOfDeviceStack, irp);

    if (status == STATUS_PENDING) {

        dueTime.QuadPart = -10000 * Milliseconds;

        status = KeWaitForSingleObject(
                            &event,
                            Executive,
                            KernelMode,
                            FALSE,
                            &dueTime
                            );

        if (status == STATUS_TIMEOUT) {

            if (InterlockedExchange((PVOID)&lock, IRPLOCK_CANCEL_STARTED) == IRPLOCK_CANCELABLE) {

                //
                // You got it to the IRP before it was completed. You can cancel
                // the IRP without fear of losing it, because the completion routine
                // does not let go of the IRP until you allow it.
                //
                IoCancelIrp(irp);

                //
                // Release the completion routine. If it already got there,
                // then you need to complete it yourself. Otherwise, you got
                // through IoCancelIrp before the IRP completed entirely.
                //
                if (InterlockedExchange(&lock, IRPLOCK_CANCEL_COMPLETE) == IRPLOCK_COMPLETED) {
                    IoCompleteRequest(irp, IO_NO_INCREMENT);
                }
            }

            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);

            ioStatus.Status = status; // Return STATUS_TIMEOUT

        } else {

            status = ioStatus.Status;
        }
    }

    return status;
}

NTSTATUS
MakeSynchronousIoctlWithTimeOutCompletion(
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp,
    IN PVOID            Context
    )
{
    PLONG lock;

    lock = (PLONG) Context;

    if (InterlockedExchange((PVOID)&lock, IRPLOCK_COMPLETED) == IRPLOCK_CANCEL_STARTED) {
        //
        // Main line code has got the control of the IRP. It will
        // now take the responsibility of completing the IRP.
        // Therefore...
        return STATUS_MORE_PROCESSING_REQUIRED;
    }

    return STATUS_CONTINUE_COMPLETION ;
}
游客

返回顶部