Richtlinien zum Schreiben von DPC-Routinen
Beachten Sie beim Schreiben einer DpcForIsr - oder CustomDpc-Routine die folgenden Punkte:
Eine DpcForIsr - oder CustomDpc-Routine muss ihren Zugriff auf ein physisches Gerät und alle informationen oder Ressourcen, die der Treiber verwaltet, mit anderen Routinen des Treibers synchronisieren, die auf dieselben Geräte- oder Speicherstandorte zugreifen.
Wenn eine DpcForIsr - oder CustomDpc-Routine das Gerät oder den Zustand mit einem ISR teilt, muss sie KeSynchronizeExecution aufrufen und die Adresse einer vom Treiber bereitgestellten SynchCritSection-Routine angeben, die das Gerät programmiert oder auf den freigegebenen Zustand zugreift. Weitere Informationen finden Sie unter Verwenden kritischer Abschnitte.
Wenn eine DpcForIsr - oder CustomDpc-Routine zustands- oder ressourcenfreigabet, z. B. eine ineinander verriegelte Warteschlange oder ein Timerobjekt, mit anderen Routinen als einem ISR, muss sie den freigegebenen Zustand oder die Ressourcen mit einer vom Treiber initialisierten Executive Spin-Sperre schützen. Weitere Informationen finden Sie unter Spin Locks.
DpcForIsr - und CustomDpc-Routinen werden unter IRQL = DISPATCH_LEVEL ausgeführt, wodurch der Satz von Supportroutinen eingeschränkt wird, die sie aufrufen können.
Beispielsweise können DpcForIsr - und CustomDpc-Routinen weder auf auslagerungsfähigen Arbeitsspeicher zugreifen noch zuordnen, und sie können nicht warten, bis Kernelverteilerobjekte auf den signalierten Zustand festgelegt werden. Andererseits können sie die Executive-Spin-Sperre eines Treibers mit KeAcquireSpinLockAtDpcLevel und KeReleaseSpinLockFromDpcLevel erwerben und freigeben, die schneller als KeAcquireSpinLock und KeReleaseSpinLock ausgeführt werden.
Obwohl eine DPC-Routine keine blockierenden Aufrufe tätigen kann, kann sie ein Arbeitselement in eine Warteschlange stellen, um in einem Systemarbeitsthread auszuführen, der bei IRQL ausgeführt wird, PASSIVE_LEVEL. Das Arbeitselement kann blockierende Aufrufe ausführen, die auf Dispatcherobjekte warten. Um ein Arbeitselement in eine Warteschlange zu stellen, ruft eine DpcForIsr-Routine in der Regel eine Routine wie IoQueueWorkItem auf, und eine CustomDpc-Routine ruft normalerweise die ExQueueWorkItem-Routine auf.
DpcForIsr - und CustomDpc-Routinen sind in der Regel für das Starten des nächsten E/A-Vorgangs auf dem Gerät verantwortlich.
Bei physischen Gerätetreibern auf der niedrigsten Ebene, die direkte E/A verwenden, kann diese Verantwortung die Verwendung einer SynchCritSection-Routine umfassen, um das Gerät so zu programmieren, dass mehr Daten übertragen werden, um die aktuelle IRP zu erfüllen, bevor der Treiber IoStartNextPacket aufruft.
DpcForIsr - und CustomDpc-Routinen sollten nur für kurze Zeiträume ausgeführt werden und sollten so viel Verarbeitung wie möglich an Workerthreads delegieren.
Während eine DPC-Routine auf einem Prozessor ausgeführt wird, werden alle Threads nicht auf demselben Prozessor ausgeführt. Andere DPC-Routinen, die in der Warteschlange stehen und zur Ausführung bereit sind, können nicht ausgeführt werden, bis die aktuelle DPC-Routine abgeschlossen ist. Um eine beeinträchtigte Reaktionsfähigkeit des Systems zu vermeiden, sollte eine typische DPC-Routine bei jedem Aufruf nicht mehr als 100 Mikrosekunden lang ausgeführt werden. Wenn ein Task länger als 100 Mikrosekunden benötigt und bei IRQL gleich DISPATCH_LEVEL ausgeführt werden muss, sollte die DPC-Routine nach 100 Mikrosekunden enden und eine oder mehrere CustomTimerDpc-Routinen für den Abschluss der Aufgabe zu einem späteren Zeitpunkt planen. Weitere Informationen zu CustomTimerDpc-Routinen finden Sie unter Timer-Objekte und DPCs.
Eine DPC-Routine sollte nur Aufgaben ausführen, die bei DISPATCH_LEVEL ausgeführt werden müssen, und dann alle verbleibenden interruptbezogenen Arbeiten an Threads delegieren, die mit IRQL = PASSIVE_LEVEL ausgeführt werden. Beispielsweise kann eine DPC-Routine ein Arbeitselement in eine Warteschlange stellen, um es in einem System workerthread auszuführen.
DPC-Routinen, die die KeStallExecutionProcessor-Routine aufrufen, um die Ausführung zu verzögern, dürfen keine Verzögerungen von mehr als 100 Mikrosekunden angeben.
Verwenden Sie die Leistungsanalysetools im WDK, um die Ausführungszeiten von DPC-Routinen auszuwerten. Ein Beispiel, das das Tracelog-Tool zum Überwachen der DPC-Ausführungszeiten verwendet, finden Sie unter Beispiel 15: Messen der DPC/ISR-Zeit.
Wenn der Treiber DMA verwendet und seine AdapterControl-RoutineKeepObject oder DeallocateObjectKeepRegisters zurückgibt (wodurch der System-DMA-Controllerkanal oder der Bus-master-Adapter für zusätzliche Übertragungsvorgänge beibehalten wird), ist die DpcForIsr- oder CustomDpc-Routine für die Freigabe des Adapterobjekts oder der Kartenregister mit FreeAdapterChannel oder FreeMapRegisters verantwortlich. bevor das aktuelle IRP abgeschlossen und das Steuerelement zurückgegeben wird.
Wenn ein physischer Gerätetreiber der niedrigsten Ebene ein Controllerobjekt zum Synchronisieren von E/A-Vorgängen über den Controller mit angefügten Geräten einrichtet, ist die DpcForIsr - oder CustomDpc-Routine für das Freigeben des Controllerobjekts mithilfe von IoFreeController verantwortlich, bevor die aktuelle IRP abgeschlossen wird und die Steuerung zurückgibt.
DpcForIsr- und CustomDpc-Routinen sind in der Regel für die Protokollierung aller Gerätefehler verantwortlich, die während der Verarbeitung einer bestimmten Anforderung aufgetreten sind, die aktuelle Anforderung bei Bedarf und Möglich erneut auszuführen, und für das Festlegen des E/A-status-Blocks und das Aufrufen von IoCompleteRequest für die aktuelle IRP.
Wenn Treiber und Gerät überlappende E/A-Vorgänge unterstützen, muss der Treiber die Regeln für die Behandlung überlappender E/A-Vorgänge befolgen.
Die DpcForIsr - oder CustomDpc-Routine eines beliebigen Treibers schließt die E/A-Verarbeitung in der Regel nur für eine Teilmenge der öffentlichen E/A-Steuerungscodes ab, die der Treiber unterstützen muss. Insbesondere schließt die DPC-Routine Vorgänge für Gerätesteuerungsanforderungen mit den folgenden Merkmalen ab:
Anforderungen, die den Zustand des physischen Geräts ändern
Anforderungen, die die Rückgabe von inhärent flüchtigen Informationen über das physische Gerät erfordern