Använda en IoTimer-rutin

Medan timern för det associerade enhetsobjektet är aktiverad anropas IoTimer- rutin ungefär en gång per sekund. Men eftersom de intervall med vilka varje IoTimer rutin anropas beror på systemklockans upplösning, förutsätter du inte att en IoTimer- rutin anropas exakt på en sekunds gräns.

Notera An IoTimer rutin, likt alla DPC-rutiner, anropas på IRQL = DISPATCH_LEVEL. Medan en DPC-rutin körs hindras alla trådar från att köras på samma processor. Drivrutinsutvecklare bör noggrant utforma sina IoTimer- rutiner att köra under så kort tid som möjligt.

Det vanligaste användningsområdet för en IoTimer- rutin är att stänga av enhets-I/O-operationer vid en tidsgräns för en IRP. Överväg följande scenario för att använda en IoTimer- rutin som en körningstimer i en enhetsdrivrutin:

  1. När enheten startas initierar drivrutinen en timerräknare i enhetstillägget till -1, vilket anger att det inte finns några aktuella I/O-åtgärder för enheten och anropar IoStartTimer precis innan den returnerar STATUS_SUCCESS.

    Varje gång IoTimer-rutin anropas kontrollerar den om timerräknaren är -1 och returnerar i så fall kontrollen.

  2. Drivrutinens StartIo--rutin initierar timerräknaren i enhetstillägget till en övre gräns, plus ytterligare en sekund om IoTimer-rutin precis har körts. Den använder sedan KeSynchronizeExecution för att anropa en SynchCritSection_1 rutin, som programmerar den fysiska enheten för den åtgärd som begärs av den aktuella IRP.

  3. Förarens ISR återställer timer-räknaren till -1 innan den köar förarens DpcForIsr-rutin eller en CustomDpc-rutin.

  4. Varje gång IoTimer rutin anropas kontrollerar den om timerräknaren har återställts av ISR till -1 och i så fall returnerar kontrollen. Annars använder IoTimer rutinen KeSynchronizeExecution för att anropa rutinen SynchCritSection_2, vilket justerar timern genom ett visst antal förarbestämda sekunder.

  5. SynchCritSection_2-rutinen returnerar TRUE till IoTimer-rutinen så länge den aktuella begäran ännu inte har överskridit tidsgränsen. Om timerräknaren går till noll återställer SynchCritSection_2-rutinen timerräknaren till ett förarbestämt återställningstimeoutvärde, anger en återställningsförväntad flagga för sig själv (och för DpcForIsr) i sitt kontextområde, försöker återställa enheten och returnerar TRUE.

    Den SynchCritSection_2 rutinen kommer att anropas igen om återställningsoperationen också går ut över tidsgränsen för enheten när den returnerar FALSE. Om återställningen lyckas avgör DpcForIsr--rutinen att enheten har återställts från reset-expected-flaggan och försöker skicka begäran igen, upprepar åtgärderna i StartIo-rutinen enligt beskrivningen i det andra steget.

  6. Om SynchCritSection_2-rutinen returnerar FALSE-förutsätter IoTimer- rutin att den fysiska enheten är i ett okänt tillstånd eftersom ett försök att återställa den redan har misslyckats. Under dessa omständigheter köar rutinen IoTimer en rutin CustomDpc och returnerar. Den här CustomDpc- rutin loggar ett I/O-fel på en enhet, anropar IoStartNextPacket, misslyckas att behandla den aktuella IRP och returnerar.

Om den här enhetsdrivrutinens ISR återställer den delade timerräknaren till -1, enligt beskrivningen i steg 3, slutför drivrutinens DpcForIsr rutin den avbrottsdrivna I/O-bearbetningen av den aktuella IRP:n. Räknaren för återställningstimer anger att enhetens I/O-åtgärd inte har överskriden tidsgräns, så IoTimer- rutin behöver inte ändra timerräknaren.

Under de flesta omständigheter minskar den föregående SynchCritSection_2 rutinen helt enkelt timerräknaren. Den SynchCritSection_2 rutinen försöker bara återställa enheten om den aktuella I/O-åtgärden har överskriden tidsgräns, vilket anges när timerräknaren går till noll. Och bara om ett försök att återställa enheten redan har misslyckats returnerar SynchCritSection_2 rutin FALSE- till IoTimer- rutin.

Därför tar både den föregående IoTimer rutin och dess hjälp SynchCritSection_2 rutin mycket lite tid att utföra under normala omständigheter. Genom att använda en IoTimer- rutin på det här sättet säkerställer en enhetsdrivrutin att varje giltig I/O-begäran kan göras om, om det behövs, och att en CustomDpc- rutin endast misslyckas med en IRP om ett fel som inte kan identifieras av maskinvaran förhindrar att IRP uppfylls. Dessutom tillhandahåller drivrutinen den här funktionen till mycket lite kostnad under körningstiden.

Enkelheten i föregående scenario beror på en enhet som bara utför en åtgärd i taget och på en drivrutin som normalt inte överlappar I/O-åtgärder. En drivrutin som utför överlappande enhets-I/O-åtgärder, eller en drivrutin på högre nivå som använder en IoTimer- rutin för att hantera timeout av en uppsättning av förarallokerade IRP:er som skickas till flera kedjor av lägre drivrutiner, skulle ha mer komplexa timeout-scenarier att hantera.