Condividi tramite


Esempi di sincronizzazione

Gli esempi seguenti illustrano cosa deve fare un minidriver per quanto riguarda la sincronizzazione e include esempi di quando la sincronizzazione non deve essere usata:

  • Esempio 1: Minidriver con isr funzionante

    Se la sincronizzazione della classe di flusso è attivata, tutti i punti di ingresso del minidriver vengono chiamati in irQL generati tramite KeSynchronizeExecution, il che significa che il livello IRQ dell'adattatore e tutti i livelli IRQ inferiori vengono mascherati quando il minidriver esegue il codice. Pertanto, è fondamentale che il minidriver esegua solo una piccola quantità di lavoro in questa modalità.

    Il minidriver non deve eseguire codice che in genere richiede più di 10-20 microsecondi in corrispondenza di IRQL generato. Se si usa la build di debug di stream.sys, la classe di flusso registra la quantità di tempo impiegato in IRQL generato e asserisce se il driver sta spendendo troppo tempo. Se il minidriver deve semplicemente programmare i registri DMA hardware per una richiesta o semplicemente deve leggere le porte nel relativo ISR, in genere è accettabile eseguire tutte le operazioni di elaborazione in IRQL generato.

    Se il minidriver deve eseguire l'elaborazione che richiede più di pochi microsecondi, ad esempio un minidriver che trasferisce i dati tramite PIO, il minidriver deve usare StreamClassCallAtNewPriority per pianificare un callback DISPATCH_LEVEL. Nel callback, il minidriver può richiedere fino a circa 1/2 a 1 millisecondo per eseguire l'elaborazione. Una cosa da ricordare quando in questa modalità è che il callback DISPATCH_LEVEL non è sincronizzato con l'ISR.

    Questa mancanza di sincronizzazione non è un problema se l'hardware rimane stabile quando il minidriver accede alle risorse (ad esempio, porte o una coda) durante il callback e nell'ISR. Tuttavia, se l'instabilità potrebbe essere un problema, il minidriver deve usare StreamClassCallAtNewPriority per pianificare un callback con priorità alta in cui il callback DISPATCH_LEVEL tocca le risorse condivise con le risorse usate dall'ISR.

    Si noti che un callback con priorità ALTA equivale a chiamare KeSynchronizeExecution. KeSynchronizeExecution richiede che il minidriver faccia riferimento a diversi parametri che StreamClassCallAtNewPriority non ha, ma in generale i due comportano lo stesso comportamento.

    Se il minidriver deve eseguire solo occasionalmente codice che richiede più di 1/2 a 1 millisecondo o occasionalmente deve chiamare i servizi in PASSIVE_LEVEL (ad esempio in fase di inizializzazione), è possibile impostare StreamClassCallAtNewPriority su BASSA priorità per acquisire un thread di lavoro PASSIVE_LEVEL. Si noti che un callback con priorità bassa non è sincronizzato con nulla e che il minidriver potrebbe ricevere nuove richieste (presupponendo che il parametro ReadyForNextRequest NotificationType sia in sospeso) o una chiamata ISR quando si esegue un callback con priorità bassa.

  • Esempio 2: Minidriver senza ISR

    Se la sincronizzazione della classe di flusso è attivata, i punti di ingresso del minidriver vengono tutti chiamati in DISPATCH_LEVEL. Il minidriver può eseguire l'elaborazione di un massimo di 1/2 a 1 millisecondo di durata senza dover regolare la priorità. Se il minidriver deve eseguire solo occasionalmente codice che richiede più di 1/2 millisecondi o occasionalmente deve chiamare i servizi in PASSIVE_LEVEL (ad esempio in fase di inizializzazione), è possibile usare StreamClassCallAtNewPriority con priorità LOW per acquisire un thread di lavoro PASSIVE_LEVEL. Si noti che un callback con priorità bassa non è sincronizzato con nulla e il minidriver potrebbe ricevere nuove richieste (presupponendo che il parametro ReadyForNextRequest NotificationType sia in sospeso) quando si esegue un callback con priorità bassa.

  • Quando la sincronizzazione della classe di flusso non deve essere usata

    Di seguito sono riportati esempi di situazioni in cui la sincronizzazione delle classi di flusso non deve essere usata. tra cui:

    • Quando i driver spesso (più del 20% delle richieste ricevute dal minidriver) devono eseguire l'elaborazione che richiede più di 1 millisecondo o devono chiamare frequentemente servizi PASSIVE_LEVEL, ad esempio i servizi Microsoft DirectDraw. Quando si usa la versione di debug di stream.sys, la classe di flusso asserisce entrambi questi casi e si interrompe se vengono rilevati con la sincronizzazione attivata.

    • Quando il minidriver è un filtro senza hardware associato. Un minidriver di questo tipo deve essere in esecuzione in PASSIVE_LEVEL poiché non è presente alcun hardware sottostante da sincronizzare con e il minidriver esegue in genere molte operazioni di elaborazione. In questo caso è più facile eseguire la sincronizzazione in questo caso rispetto allo spreco di sovraccarico usando la sincronizzazione delle classi di flusso. Se necessario, usare mutex per proteggere le code.

      I bug nel codice di sincronizzazione possono spesso essere difficili da trovare e in alcuni ambienti (ad esempio sistemi operativi basati su NT in esecuzione su sistemi multiprocessore) i bug possono essere visualizzati solo dopo molte ore di stress. In base all'esperienza con i fornitori, questi non sono i tipi di cose che la maggior parte dei fornitori hanno la capacità o il desiderio di eseguire il debug. Solo i writer di driver che hanno familiarità con la scrittura di driver di dispositivo WDM completamente asincroni devono tentare di eseguire la propria sincronizzazione.

    • Quando il minidriver è un driver di tipo bus-on-bus (ad esempio, un driver di periferica USB o 1394) che non si preoccupa davvero della sincronizzazione dell'hardware effettivo, ma chiama solo le richieste al livello successivo a PASSIVE_LEVEL e riceve i callback in genere a DISPATCH_LEVEL.