阅读:2126回复:2
请看下这段代码
其实就是向USBD提交IRP的代码,不过增加了超时取消机制。取消的代码参考了微软网站上的代码,主要有几点考虑:
1. 取消是一个过程,所以在开始取消和取消完成时进行判断,从而得到完成函数与取消过程执行时序; 2. 由于完成函数中要访问事件,所以在提交代码中确保资源释放前完成函数已经被调用了。但由于后面的问题不明确,不知道,完成函数是否会被两次调用,从而有可能出现等到第一次事件后就释放了资源,而第二次调用在设置时间时必定蓝屏。 主要的疑问,在代码中注释出来了: 1. 如果在取消的过程中, 完成函数被调用了, 那么完成函数是否还会再被调用一次?也就是说, 1那里的事件应不应该设置? 2. 如果取消完成时, 完成函数都未被调用。那随后完成函数是否会被再次调用?2那里的事件应不应该设置? 3. 如果IoCallDriver的返回值不是STATUS_PENDING,那么该IRP应该是同步完成的吧.这种情况下,完成函数是否会被调用? 其实1,2都可归结为对IoCancelIrp的调用是否会导致对完成函数的调用?这又细分为1,2两种情况,即如果完成函数已经执行,IoCancelIrp是否会导致完成函数再次调用;如果完成函数根本未执行, IoCancelIrp是否会导致完成函数的调用?下面的代码是基于否定的回答来写的。但调用IoSetIoCompletionRoutine时有一个参数invokeOnCancel,推测其意义则应该被调用?不解中。。。 问题3则是关于IoCallDriver... NTSTATUS UsbSyncIrpComplete( IN PDEVICE_OBJECT device, IN PIRP irp, IN PVOID context) { PIF_IO_CONTEXT hwContext; completionRoutineCalled = TRUE; hwContext = (PIF_IO_CONTEXT) context; if( InterlockedExchange((PVOID)&hwContext->lock, IRPLOCK_COMPLETED) == IRPLOCK_CANCEL_STARTED ) { return STATUS_MORE_PROCESSING_REQUIRED; } KeSetEvent(&hwContext->done, 0, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; #if 0 if (InterlockedExchange(&hwContext->lock, IRPLOCK_COMPLETED) == IRPLOCK_CANCEL_STARTED) { return STATUS_MORE_PROCESSING_REQUIRED; } return STATUS_CONTINUE_COMPLETION; PSYNC_IRP_CONTEXT irpContext; irpContext = (PSYNC_IRP_CONTEXT)context; NdisAcquireSpinLock( &irpContext->lock ); KeSetEvent( &irpContext->irpDone, IO_NO_INCREMENT, FALSE ); NdisReleaseSpinLock( &irpContext->lock ); return STATUS_MORE_PROCESSING_REQUIRED; #endif } NTSTATUS UsbSyncSubmitIrpToUSBD( IN PADAPTER_CONTEXT adapter, IN ULONG controlCode, IN PVOID arg1, IN PVOID arg2) { NTSTATUS status, waitStatus; IO_STATUS_BLOCK statusBlock; PIF_IO_CONTEXT context; PIRP irp; PIO_STACK_LOCATION lowerIrpStack; IRPLOCK lock; LARGE_INTEGER waitTime; BOOLEAN cancelled; status = STATUS_UNSUCCESSFUL; waitTime.QuadPart = -CFG_HW_USB_TIMEOUT; do { // --------------------------------------------------------------------- // Build internal IOCTL IRP // --------------------------------------------------------------------- context = AllocateIOContext(adapter); if( NULL == context ) { DBGERROR( " Failed to allocate irp for USB syncronous operation!\n" ); status = STATUS_INSUFFICIENT_RESOURCES; break; } KeClearEvent(&context->done); context->lock = IRPLOCK_CANCELABLE; irp = context->irp; lowerIrpStack = IoGetNextIrpStackLocation( irp ); ASSERT( lowerIrpStack != NULL ); lowerIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; lowerIrpStack->Parameters.DeviceIoControl.IoControlCode = controlCode; lowerIrpStack->Parameters.Others.Argument1 = arg1; lowerIrpStack->Parameters.Others.Argument2 = arg2; if( AcquireAdapter(adapter) ) { IoSetCompletionRoutine( irp, UsbSyncIrpComplete, context, TRUE, TRUE, TRUE ); // ----------------------------------------------------------------- // Submit the IRP and wait if necessary // ----------------------------------------------------------------- status = IoCallDriver( adapter->hc.nextDevice, irp ); if( STATUS_PENDING == status ) { status = KeWaitForSingleObject( &context->done, Executive, KernelMode, FALSE, &waitTime ); if( STATUS_TIMEOUT == status ) { DBGERROR( " Usb operation timeout!\n" ); // 开始取消时,IRP还未被完成函数处理, 则开始取消 if( InterlockedExchange((PVOID)&context->lock, IRPLOCK_CANCEL_STARTED) == IRPLOCK_CANCELABLE ) { cancelled = IoCancelIrp(irp); // 1. 如果取消过程中完成函数已经被调用了,那么IoCancelIrp是否会导致完成函数再次被调用。也就是说, 完成函数是被调用2次呢, 还是1次? if( InterlockedExchange((PVOID)&context->lock, IRPLOCK_CANCEL_COMPLETE) == IRPLOCK_COMPLETED ) { DBGTRACE("Irp completed during cancelling\n"); KeSetEvent( &context->done, 0, FALSE ); } // 2. 否则成功取消了, 完成函数应该没机会被调用? else { DBGTRACE("Irp cancelled before completion\n"); KeSetEvent( &context->done, 0, FALSE ); } } // 开始取消前, IRP已经完成了, 则完成函数已经设置完成事件 else { DBGTRACE("Irp completed before cancel\n"); } status = irp->IoStatus.Status; //KeWaitForSingleObject( &irpContext.irpDone, Executive, KernelMode, FALSE, NULL ); while( waitStatus = KeWaitForSingleObject( &context->done, Executive, KernelMode, FALSE, &waitTime ) ) { DBGTRACE("IRP Status: %08X\n", status); NdisMSleep(2000); } } else { DBGTRACE( " IRP no timeout[%X]\n", status ); while( waitStatus = KeWaitForSingleObject( &context->done, Executive, KernelMode, FALSE, &waitTime ) ) { NdisMSleep(2000); } } } // 3. 如果IRP未pending,则该IRP应该是同步完成的,完成函数是否被调用? else if( NT_SUCCESS(status) ) { status = STATUS_SUCCESS; DBGTRACE( " Control IRP success[%X]\n", status ); while( waitStatus = KeWaitForSingleObject( &context->done, Executive, KernelMode, FALSE, &waitTime ) ) { NdisMSleep(2000); } } else { status = irp->IoStatus.Status; DBGTRACE( " Control IRP error[%X]\n", status ); while( waitStatus = KeWaitForSingleObject( &context->done, Executive, KernelMode, FALSE, &waitTime ) ) { NdisMSleep(2000); } } ReleaseAdapter( adapter ); } //IoFreeIrp( irp ); FreeIOContext(adapter, context); } while( FALSE ); return status; } |
|
沙发#
发布于:2007-11-13 12:03
明白了, 如果在触发取消的那个时间点完成函数已经触发,则取消失败,不会再次调用完成函数;否则取消成功,完成函数也会被调用。
完成函数只会被调用一次 |
|
驱动小牛
![]() |
板凳#
发布于:2008-05-09 10:53
普及知识,谢谢
|