if (QueueEntry!=NULL) {

  PIRP Irp = CONTAINING_RECORD(QueueEntry, IRP, Tail.Overlay.DeviceQueueEntry);

  dx->AbcCurrentIrp = Irp;

  IoReleaseCancelSpinLock(OldIrql);

  AbcStartIo2(DeviceObject, Irp);

 } else {

  dx->AbcCurrentIrp = NULL;

  IoReleaseCancelSpinLock(OldIrql);

 }

}

VOID AbcStartIo2(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {

 PABC_DEVICE_EXTENSION dx = (PABC_DEVICE_EXTENSION)fdo->DeviceExtension);

 PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);

 KIRQL Oldlrql;

 IoAcquireCancelSpinLock(&OldIrql);

 if (Irp->Cancel) {

  IoReleaseCancelSpinLock(OldIrql);

  return;

 }

 IoSetCancelRoutine(Irp, NULL);

 IoReleaseCancelSpinLock(OldIrql);

 // Process and complete request

 // …

 // Start next packet

 AbcStartNextPacket2(DeviceObject);

}

IRP Cancelling and Cleanup

Cancelling IRPs in supplemental device queues can use exactly the same techniques as the standard device queue. In this example, the cancel routine is removed when AbcStartIo2 is called. As shown in Listing 16.9, if the IRP to cancel is the current IRP, it is completed with a cancelled status in AbcCancelIrp. When AbcStartIo2 starts, it checks the Cancel flag and removes the cancel routine.

The Cleanup IRP handling should use exactly the same techniques as the WdmIo driver. The WdmIo driver uses a Timeout variable to stop an IRP that is being processed. You will need to use some similar technique if any of your IRPs may take a long time to be processed.

Listing 16.9 Supplemental device queue IRP cancel routine

VOID AbcCancelIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {

 PABC_DEVICE_EXTENSION dx = (PABC_DEVICE_EXTENSION)fdo->DeviceExtension;

 if (Irp=dx->AbcCurrentIrp) {

  IoReleaseCancelSpinLock(Irp->CancelIrq1);

  CompleteIrp(Irp, STATUS_CANCELLED);

  AbcStartNextPacket2(DeviceObject, TRUE);

 } else {

  KeRemoveEntryDeviceQueue(&dx->AbcIrpQueue, &Irp->Tail.Overlay.DeviceQueueEntry);

  IoReleaseCancelSpinLock(Irp->CancelIrql);

  CompleteIrp(Irp, STATUS_CANCELLED);

 }

}

Conclusion

This chapter has shown how to queue IRPs for serial processing in a driver's StartIo routine. It has then shown how to cope with the necessary evil of cancelling IRPs. Make sure you clean up any IRPs that are still not completed when the device handle is being closed. Use techniques similar to that used in the example WdmIoCancel application to test that cancelling and cleanup happen correctly.

The next chapter inspects the next part of the WdmIo and PHDIo drivers, how to handle interrupts and do interrupt-driven programmed I/O. It also looks at timers, both for IRP time-outs in the order of seconds, and custom timers for finer grain intervals.

Chapter 17

Interrupt-Driven I/O

This chapter shows how the WdmIo and PHDIo drivers handle interrupts, use Deferred Procedure Calls (DPCs), and catch time-outs. It shows how Read and Write interrupt-driven I/O is started and demonstrates how interrupt handling routines should work.

A driver's interrupt handler must service a hardware device's immediate needs. Any major processing must wait until a driver's DPC routine runs. Eventually, the DPC completes the read or write request and starts the next queued IRP.

The chapter also covers two types of timer. A basic 'one-second interval' timer is best used to implement a time-out for interrupt-driven operations. However, custom timers and their associated Custom DPCs can be used for finer grain timing.

Interrupt Handling

First, let me be clear exactly what a hardware interrupt is. Devices that generate interrupts use an electrical signal to indicate that some special condition has occurred. The interrupt system is designed to stop the processor (or one of the processors) in its tracks — as soon as possible — and start some code to service the interrupt.

When an interrupt occurs, the processor saves a small amount of information on the kernel stack: the processor registers and the instruction pointer before the interrupt. This is just enough to restore the context when the interrupt service routine has completed.

The Nature of the Beast

Interrupts are usually used when something important has happened, or when a driver ought to do something important to its hardware device. Following are some example interrupt events.

• From the modem: I have just received a character. Come and get it! Another might arrive soon and overwrite this one.

• From the disk controller: I have just finished a DMA transfer of a sector of data. What shall I do now?

• From the printer: I have just printed a character. Give me another!

• From the printer: I have just run out of paper. Please tell the user to buy some more!

As you can see, not all interrupts are equally important. Of the previous four situations, the modem and disk controller interrupts are the most important.

x86 processors have a NonMaskable Interrupt (NMI) pin input and an Interrupt (INTR) pin input, with all normal device interrupts sharing the INTR input. External 8259A controllers are used to provide several interrupt lines to devices (i.e., IRQ0-IRQ15). IRQ0-IRQ15 share the INTR pin. An interrupt vector specifies the memory location that contains the address of the interrupt service routine. The 8259A controllers provide a different vector for each IRQ number. Therefore, IRQ0-IRQ15 each have their own interrupt service routines inside the Windows kernel.

x86 processors prioritize their interrupts in a simple way. Processor exceptions have the highest priority. NMI interrupts come next and then INTR interrupts. The INTR interrupts are maskable, as they can be disabled by setting a bit in the processor status register.

If an INTR interrupt occurs, its service routine will run until completion, stopping other INTR interrupts from occurring. However, an NMI interrupt could still butt in half-way through the INTR service routine. An interrupt service routine should do its job quickly, as it could stop other equally important INTR interrupts from being serviced. The interrupt latency is the time between a device asserting its interrupt signal and its service routine starting. Help keep the interrupt latency down for all drivers by making your interrupt service routine run quickly.

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату
×