Condividi tramite


Sincronizzazione del Codice di Interruzione

I fattori seguenti complicano il codice driver che gestisce gli interrupt hardware nei sistemi multiprocessore:

  • Ogni volta che un dispositivo genera un'interruzione, fornisce informazioni specifiche relative all'interruzione, che sono volatili perché possono essere sovrascritte alla successiva interruzione che il dispositivo genera.

  • I dispositivi interrompono a livelli IRQL relativamente elevati e le routine di servizio di interrupt (ISR) possono interrompere l'esecuzione di altro codice del driver.

  • Per gli interrupt DIRQL, l'ISR deve essere eseguito in DIRQL mantenendo un blocco spin fornito dal driver, in modo che l'ISR possa impedire interruzioni aggiuntive mentre salva informazioni volatili. DIRQL impedisce l'interruzione del processore corrente e il blocco spin impedisce l'interruzione da parte di un altro processore.

  • L'ISR deve essere eseguito rapidamente perché il dispositivo non può interrompersi durante l'esecuzione dell'ISR. Tempi di esecuzione ISR lunghi possono rallentare il sistema o causare la perdita di dati.

  • Sia la routine ISR che la chiamata di procedura posticipata (DPC) devono in genere accedere a un'area di archiviazione in cui l'ISR archivia i dati volatili del dispositivo. Queste routine devono essere sincronizzate tra loro in modo che non accingano contemporaneamente all'area di archiviazione.

A causa di tutti questi fattori, è necessario usare le regole seguenti durante la scrittura di codice driver che gestisce gli interrupt:

  • Solo la funzione di callback EvtInterruptIsr accede ai dati di interrupt volatili, ad esempio i registri dei dispositivi che contengono informazioni di interrupt.

    La funzione di callback EvtInterruptIsr deve spostare i dati volatili in un buffer di dati interrupt definito dal driver a cui può accedere la funzione di callback EvtInterruptDpc del driver, la funzione di callback EvtInterruptWorkItem o più funzioni di callback EvtDpcFunc .

    Se il driver fornisce funzioni di callback EvtInterruptDpc o EvtInterruptWorkItem per gli oggetti interrupt, la posizione migliore per archiviare i dati di interrupt è lo spazio di contesto dell'oggetto interrupt. Le funzioni di callback dell'oggetto interrupt possono accedere allo spazio di contesto dell'oggetto utilizzando l'handle dell'oggetto ricevuto.

    Se il driver fornisce più funzioni di callback EvtDpcFunc per ogni funzione di callback EvtInterruptIsr , è possibile archiviare i dati di interrupt nello spazio di contesto di ogni oggetto DPC.

  • Tutto il codice driver che accede al buffer dei dati di interrupt deve essere sincronizzato in modo che solo una routine acceda ai dati una per volta.

    Per gli oggetti interrupt DIRQL, la funzione di callback EvtInterruptIsr accede a questo buffer di dati in IRQL = DIRQL mantenendo il blocco spin fornito dal driver dell'oggetto interrupt. Pertanto, tutte le routine che accedono al buffer devono essere eseguite a livello DIRQL mentre mantengono lo spinlock. In genere, la funzione di callback EvtInterruptDpc o EvtDpcFunc dell'interrupt è l'unica altra routine che deve accedere al buffer.

    Tutte le routine che accedono a un buffer di dati interrupt, ad eccezione della funzione di callback EvtInterruptIsr , devono eseguire una delle operazioni seguenti:

    Entrambe queste tecniche consentono alla funzione EvtInterruptDpc o EvtDpcFunc di accedere ai dati di interrupt in DIRQL mantenendo il blocco spin dell'interrupt. DIRQL impedisce l'interruzione del processore corrente e il blocco spin impedisce l'interruzione da parte di un altro processore.

    Se il dispositivo supporta più vettori di interrupt o messaggi e si desidera sincronizzare la gestione di questi interrupt da parte del driver, è possibile assegnare un singolo lock di spin a più oggetti di interrupt DIRQL. Il framework determina il valore DIRQL più elevato del set di interrupt e acquisisce sempre il blocco spin in corrispondenza di tale DIRQL in modo che il codice sincronizzato non possa essere interrotto da eventuali vettori di interrupt o messaggi nel set.

    Per gli oggetti interrupt a livello passivo, il framework acquisisce il blocco interrupt a livello passivo prima di chiamare la funzione di callback EvtInterruptIsr del driver in IRQL = PASSIVE_LEVEL. Di conseguenza, tutte le routine che accedono al buffer devono acquisire il blocco interrupt o sincronizzare internamente l'accesso al buffer. In genere, la funzione di callback EvtInterruptWorkItem dell'interrupt è l'unica altra routine che accede al buffer. Per informazioni su come acquisire il blocco interrupt da una funzione di callback EvtInterruptWorkItem, vedere la sezione Osservazioni di quella pagina.

    È anche possibile sincronizzare la gestione del driver di più vettori di interrupt assegnando un singolo blocco di attesa a molteplici oggetti di interrupt a livello passivo.

  • Se parte del codice che gestisce gli interrupt DIRQL deve essere eseguita in IRQL = PASSIVE_LEVEL, la funzione di callback EvtInterruptDpc o EvtDpcFunc può creare uno o più elementi di lavoro in modo che il codice venga eseguito come funzioni di callback EvtWorkItem .

    In alternativa, nelle versioni 1.11 e successive di KMDF il driver può richiedere un elemento di lavoro interrupt chiamando WdfInterruptQueueWorkItemForIsr. Tenere presente che la funzione di callback EvtInterruptIsr di un driver può chiamare WdfInterruptQueueWorkItemForIsr o WdfInterruptQueueDpcForIsr, ma non entrambi.

  • Se è importante sincronizzare le funzioni di callback EvtInterruptDpc e EvtDpcFunc di un driver con le altre funzioni di callback associate a un dispositivo, il driver può impostare il membro AutomaticSerialization su TRUE nella struttura WDF_INTERRUPT_CONFIG dell'interrupt e nella struttura WDF_DPC_CONFIG dell'oggetto DPC. In alternativa, il driver può usare blocchi di selezione del framework. L'impostazione del membro AutomaticSerialization su TRUE non sincronizza una funzione di callback EvtInterruptIsr con altre funzioni di callback. Usare WdfInterruptSynchronize o WdfInterruptAcquireLock per sincronizzare una funzione di callback EvtInterruptIsr , come descritto in precedenza in questo argomento.

Per altre informazioni sulla sincronizzazione delle routine dei driver, vedere Tecniche di sincronizzazione per i driver Framework-Based.