调用顺序:IoStartPacket------>将IRP插入队列,调用StartIO------>StartIO处理完当前IRP后调用IoStartNextPacket------>IoStartNextPacket取出队列中的下一个IRP后作为参数调用StartIO------>StartIO .
驱动程序中的StartIO,CancelIO比较复杂,也很可能出错。翻了一下WDK,删除了一些无关紧要的code,贴在这里方便以后查阅:
- BOOLEAN
- IoCancelIrp(
- IN PIRP Irp
- )
- {
- PDRIVER_CANCEL cancelRoutine;
- KIRQL irql;
- BOOLEAN returnValue;
- ASSERT( Irp->Type == IO_TYPE_IRP );
- //
- // Acquire the cancel spin lock.
- //
- IoAcquireCancelSpinLock( &irql );
- //
- // Set the cancel flag in the IRP.
- //
- Irp->Cancel = TRUE;
- //
- // Obtain the address of the cancel routine, and if one was specified,
- // invoke it.
- //
- cancelRoutine = (PDRIVER_CANCEL) (ULONG_PTR) InterlockedExchangePointer( (PVOID *) &Irp->CancelRoutine, NULL );
- if (cancelRoutine) {
- Irp->CancelIrql = irql;
- cancelRoutine( Irp->Tail.Overlay.CurrentStackLocation->DeviceObject,
- Irp );
- //
- // The cancel spinlock should have been released by the cancel routine.
- //
- return(TRUE);
- } else {
- //
- // There was no cancel routine, so release the cancel spinlock and
- // return indicating the Irp was not currently cancelable.
- //
- IoReleaseCancelSpinLock( irql );
- return(FALSE);
- }
- }
- VOID
- IoStartPacket(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp,
- IN PULONG Key OPTIONAL,
- IN PDRIVER_CANCEL CancelFunction OPTIONAL
- )
- /*++
- Routine Description:
- This routine attempts to start the specified packet request (IRP) on the
- specified device. If the device is already busy, then the packet is
- simply queued to the device queue. If a non-NULL CancelFunction is
- supplied, it will be put in the IRP. If the IRP has been canceled, the
- CancelFunction will be called after the IRP has been inserted into the
- queue or made the current packet.
- Arguments:
- DeviceObject - Pointer to device object itself.
- Irp - I/O Request Packet which should be started on the device.
- Key - Key to be used in inserting packet into device queue; optional
- (if not specified, then packet is inserted at the tail).
- CancelFunction - Pointer to an optional cancel routine.
- Return Value:
- None.
- --*/
- {
- KIRQL oldIrql;
- KIRQL cancelIrql = PASSIVE_LEVEL;
- BOOLEAN i;
- //
- // Raise the IRQL of the processor to dispatch level for synchronization.
- //
- KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
- //
- // If the driver has indicated that packets are cancelable, then acquire
- // the cancel spinlock and set the address of the cancel function to
- // indicate that the packet is not only cancelable, but indicates what
- // routine to invoke should it be cancelled.
- //
- if (CancelFunction) {
- IoAcquireCancelSpinLock( &cancelIrql );
- Irp->CancelRoutine = CancelFunction;
- }
- i = KeInsertDeviceQueue( &DeviceObject->DeviceQueue,
- &Irp->Tail.Overlay.DeviceQueueEntry );
- //
- // If the packet was not inserted into the queue, then this request is
- // now the current packet for this device. Indicate so by storing its
- // address in the current IRP field, and begin processing the request.
- //
- if (!i) {
- DeviceObject->CurrentIrp = Irp;
- if (CancelFunction) {
- IoReleaseCancelSpinLock( cancelIrql );
- }
- //
- // Invoke the driver's start I/O routine to get the request going on the device.
- // The StartIo routine should handle the cancellation.
- //
- DeviceObject->DriverObject->DriverStartIo( DeviceObject, Irp );
- } else {
- //
- // The packet was successfully inserted into the device's work queue.
- // Make one last check to determine whether or not the packet has
- // already been marked cancelled. If it has, then invoke the
- // driver's cancel routine now. Note that because the cancel
- // spinlock is currently being held, an attempt to cancel the request
- // from another processor at this point will simply wait until this
- // routine is finished, and then get it cancelled.
- //
- if (CancelFunction) {
- if (Irp->Cancel) {
- Irp->CancelIrql = cancelIrql;
- Irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
- CancelFunction( DeviceObject, Irp );
- } else {
- IoReleaseCancelSpinLock( cancelIrql );
- }
- }
- }
- //
- // Restore the IRQL back to its value upon entry to this function before
- // returning to the caller.
- //
- KeLowerIrql( oldIrql );
- }
- VOID
- IopStartNextPacket(
- IN PDEVICE_OBJECT DeviceObject,
- IN LOGICAL Cancelable
- )
- /*++
- Routine Description:
- This routine is invoked to dequeue the next packet (IRP) from the
- specified device work queue and invoke the device driver's start I/O
- routine for it. If the Cancelable parameter is TRUE, then the update of
- current IRP is synchronized using the cancel spinlock.
- Arguments:
- DeviceObject - Pointer to device object itself.
- Cancelable - Indicates that IRPs in the device queue may be cancelable.
- Return Value:
- None.
- --*/
- {
- KIRQL cancelIrql = PASSIVE_LEVEL;
- PIRP irp;
- PKDEVICE_QUEUE_ENTRY packet;
- //
- // Begin by checking to see whether or not this driver's requests are
- // to be considered cancelable. If so, then acquire the cancel spinlock.
- //
- if (Cancelable) {
- IoAcquireCancelSpinLock( &cancelIrql );
- }
- //
- // Clear the current IRP field before starting another request.
- //
- DeviceObject->CurrentIrp = (PIRP) NULL;
- //
- // Remove the next packet from the head of the queue. If a packet was
- // found, then process it.
- //
- packet = KeRemoveDeviceQueue( &DeviceObject->DeviceQueue );
- if (packet) {
- irp = CONTAINING_RECORD( packet, IRP, Tail.Overlay.DeviceQueueEntry );
- //
- // A packet was located so make it the current packet for this
- // device.
- //
- DeviceObject->CurrentIrp = irp;
- if (Cancelable) {
- IoReleaseCancelSpinLock( cancelIrql );
- }
- //
- // Invoke the driver's start I/O routine for this packet.
- //
- DeviceObject->DriverObject->DriverStartIo( DeviceObject, irp );
- } else {
- //
- // No packet was found, so simply release the cancel spinlock if
- // it was acquired.
- //
- if (Cancelable) {
- IoReleaseCancelSpinLock( cancelIrql );
- }
- }
- }
- #define IoSetCancelRoutine( Irp, NewCancelRoutine ) ( /
- (PDRIVER_CANCEL) (ULONG_PTR) InterlockedExchangePointer( (PVOID *) &(Irp)->CancelRoutine, (PVOID) (ULONG_PTR)(NewCancelRoutine) ) )