Condividi tramite


Uso degli elementi di lavoro del framework

Un elemento di lavoro è un'attività eseguita da un driver in una funzione di callback degli eventi EvtWorkItem . Queste funzioni vengono eseguite in modo asincrono, in IRQL = PASSIVE_LEVEL, nel contesto di un thread di lavoro di sistema.

I driver basati su framework usano in genere elementi di lavoro se una funzione EvtInterruptDpc o EvtDpcFunc , che viene eseguita in IRQL = DISPATCH_LEVEL, deve eseguire un'elaborazione aggiuntiva in IRQL = PASSIVE_LEVEL.

In altre parole, un driver può usare elementi di lavoro se una funzione eseguita in IRQL = DISPATCH_LEVEL deve chiamare una funzione che può essere chiamata solo in IRQL = PASSIVE_LEVEL.

In genere, la funzione di callback EvtInterruptDpc o EvtDpcFunc di un driver crea un oggetto elemento di lavoro e lo aggiunge alla coda degli elementi di lavoro del sistema. Successivamente, un thread di lavoro del sistema estrae l'oggetto dalla coda e chiama la funzione di callback EvtWorkItem dell'elemento di lavoro.

Driver campione che usano elementi di lavoro

I driver di esempio basati su framework che usano task includono 1394, AMCC5933, PCIDRV e Toaster.

Configurazione di un elemento di lavoro

Per configurare un elemento di lavoro, il driver deve:

  1. Creare l'elemento di lavoro.

    Il driver chiama WdfWorkItemCreate per creare un oggetto elemento di lavoro e per identificare una funzione di callback EvtWorkItem che elabora l'elemento di lavoro.

  2. Archiviare informazioni sull'elemento di lavoro.

    In genere, i driver usano la memoria di contesto dell'oggetto elemento di lavoro per archiviare informazioni sull'attività che deve essere eseguita dalla funzione di callback EvtWorkItem . Quando viene chiamata la funzione di callback EvtWorkItem , può recuperare le informazioni accedendo a questa memoria di contesto. Per informazioni su come allocare e accedere alla memoria del contesto, vedere Framework Object Context Space.For information about how to allocate and access context memory, see Framework Object Context Space.

  3. Aggiungere l'elemento alla coda di lavoro del sistema.

    Il driver chiama WdfWorkItemEnqueue, che aggiunge l'elemento di lavoro del driver alla coda di elementi di lavoro.

Quando il driver chiama WdfWorkItemCreate, deve fornire un handle a un oggetto dispositivo del framework o a un oggetto coda del framework. Quando il sistema elimina tale oggetto, elimina anche tutti gli elementi di lavoro esistenti associati all'oggetto . L'oggetto elemento di lavoro verrà eliminato e verrà ripulito il callback associato all'elemento di lavoro prima che venga richiamato il EvtCleanupCallback dell'oggetto padre.

Per altre informazioni sulle regole di pulizia per una gerarchia di oggetti framework, vedi Ciclo di vita degli oggetti framework.

Uso della funzione callback Work-Item

Dopo aver aggiunto l'elemento alla coda di lavoro, esso rimane nella coda finché non diventa disponibile un thread di lavoro di sistema. Il thread di lavoro del sistema rimuove l'elemento di lavoro dalla coda e quindi chiama la funzione di callback EvtWorkItem del driver, passando l'oggetto del work item come input.

In genere, la funzione di callback EvtWorkItem esegue i passaggi seguenti:

  1. Ottiene informazioni fornite dal driver sull'elemento di lavoro accedendo alla memoria del contesto dell'oggetto elemento di lavoro.

  2. Esegue l'attività specificata. Se necessario, la funzione di callback può chiamare WdfWorkItemGetParentObject per determinare l'oggetto padre dell'elemento di lavoro.

  3. Chiama WdfObjectDelete per eliminare l'oggetto di elemento di lavoro o, se il driver riaccoderà l'elemento di lavoro, indica che l'handle per l'elemento di lavoro è ora disponibile per il riutilizzo.

L'attività eseguita dalla funzione di callback di ogni elemento di lavoro deve essere relativamente breve. Il sistema operativo fornisce un numero limitato di thread di lavoro di sistema, in modo che il driver possa impedire le prestazioni del sistema se usa funzioni di callback degli elementi di lavoro per eseguire attività che richiedono molto tempo.

Creazione ed eliminazione di elementi di lavoro

I driver possono usare una delle due tecniche seguenti per creare ed eliminare elementi di lavoro:

  • Usare ogni elemento di lavoro una sola volta: creare l'elemento di lavoro quando necessario ed eliminarlo immediatamente dopo l'uso.

    Questa tecnica è utile per i driver che richiedono un uso poco frequente (meno spesso di una volta al minuto) di un numero ridotto di elementi di lavoro.

    Ad esempio, la funzione di callback EvtInterruptDpc di un driver può chiamare WdfWorkItemCreate e quindi WdfWorkItemEnqueue e la funzione di callback EvtWorkItem dell'elemento di lavoro può chiamare WdfObjectDelete.

    Se il driver segue questo scenario e se la relativa funzione di callback EvtInterruptDpc riceve un valore restituito STATUS_INSUFFICIENT_RESOURCES da WdfWorkItemCreate, il driver deve essere in grado di posticipare il lavoro necessario fino a quando le risorse di sistema (in genere memoria) non diventano disponibili.

  • Creare uno o più elementi di lavoro che il driver accoda in base alle esigenze.

    Questa tecnica è utile per i driver che usano spesso elementi di lavoro (più spesso di una volta al minuto) o se la funzione di callback EvtInterruptDpc del driver non può gestire facilmente un valore restituito STATUS_INSUFFICIENT_RESOURCES da WdfWorkItemCreate.

    Il sistema non alloca un thread di lavoro a un elemento di lavoro finché il driver non chiama WdfWorkItemEnqueue. Pertanto, anche se i thread di lavoro di sistema sono una risorsa limitata, la creazione di elementi di lavoro durante l'inizializzazione di un dispositivo consuma una piccola quantità di memoria, ma non influisce in caso contrario sulle prestazioni del sistema.

    I passaggi seguenti descrivono uno scenario possibile:

    1. La funzione di callback di un driver, EvtDriverDeviceAdd, chiama WdfWorkItemCreate per ottenere un handle di attività lavorativa.
    2. La funzione di callback EvtInterruptDpc del driver crea un elenco di azioni che la funzione di callback EvtWorkItem deve eseguire e quindi chiama WdfWorkItemEnqueue usando l'handle del passaggio 1.
    3. La funzione di callback EvtWorkItem del driver esegue l'elenco di azioni e imposta un flag per indicare che la funzione di callback è stata eseguita.

    Successivamente, ogni volta che viene chiamata la funzione di callback EvtInterruptDpc del driver, deve determinare se è stata eseguita la funzione di callback EvtWorkItem . Se la funzione di callback EvtWorkItem non è stata eseguita, la funzione di callback EvtInterruptDpc non chiama WdfWorkItemEnqueue, perché l'elemento di lavoro è ancora in coda. In questo caso, la funzione di callback EvtInterruptDpc aggiorna solo l'elenco di azioni per la funzione di callback EvtWorkItem .

    Ogni elemento di lavoro è associato a un dispositivo o a una coda. Quando il dispositivo o la coda associato viene rimosso, il framework elimina tutti gli elementi di lavoro associati, quindi se si usa questa tecnica, il driver non deve chiamare WdfObjectDelete.

Alcuni driver potrebbero dover chiamare WdfWorkItemFlush per scaricare gli elementi di lavoro dalla coda di lavoro. Per un esempio di utilizzo di WdfWorkItemFlush, vedere la pagina di riferimento del metodo.

Se il driver chiama WdfObjectDelete su un elemento di lavoro in sospeso, il risultato dipende dallo stato dell'elemento di lavoro:

Stato dell'elemento di lavoro Risultato
Creato ma non accodato L'elemento di lavoro viene pulito immediatamente.
Accodato La chiamata a WdfObjectDelete attende il completamento dell'esecuzione dell'elemento di lavoro, quindi l'elemento di lavoro viene pulito
Esecuzione Se il driver chiama WdfObjectDelete dall'interno di EvtWorkItem (nello stesso thread), WdfObjectDelete restituisce immediatamente. Al termine di EvtWorkItem , l'elemento di lavoro verrà pulito. In caso contrario, WdfObjectDelete attende il completamento di EvtWorkItem.