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 , 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 la aggiunge alla coda dell'elemento di lavoro del sistema. Successivamente, un thread di lavoro di sistema dequeue l'oggetto e chiama la funzione di callback EvtWorkItem dell'elemento di lavoro.

Driver di esempio che usano elementi di lavoro

I driver basati su framework di esempio che usano elementi di lavoro includono 1394, AMCC5933, PCIDRV e Tostapane.

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 alla memoria del 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 di lavoro alla coda dell'elemento di lavoro del sistema.

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

Quando il driver chiama WdfWorkItemCreate, deve fornire un handle a un oggetto dispositivo 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 il callback dell'elemento di lavoro associato verrà eliminato prima che venga richiamato il callback EvtCleanupCallback dell'oggetto padre.

Per altre informazioni sulle regole di pulizia per una gerarchia di oggetti framework, vedere Framework Object Life Cycle.For more info about the cleanup rules for a framework object hierarchy, see Framework Object Life Cycle.

Uso della funzione callback Work-Item

Dopo aver aggiunto l'elemento di lavoro alla coda dell'elemento di lavoro, rimane nella coda fino a quando non diventa disponibile un thread di lavoro di sistema. Il thread di lavoro di sistema rimuove l'elemento di lavoro dalla coda e quindi chiama la funzione di callback EvtWorkItem del driver, passando l'oggetto elemento di lavoro 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 elemento di lavoro o, se il driver riscriva 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 compromettere le prestazioni del sistema se usa funzioni di callback degli elementi di lavoro per eseguire attività dispendiose in termini di 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 non saranno disponibili risorse di sistema (in genere memoria).

  • Creare uno o più elementi di lavoro accodabili al driver 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 utilizza una piccola quantità di memoria, ma non influisce in altro modo sulle prestazioni del sistema.

    I passaggi seguenti descrivono un possibile scenario:

    1. EvtDriverDeviceAdd della funzione di callback di un driver chiama WdfWorkItemCreate per ottenere un handle di elemento di lavoro.
    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 la funzione di callback EvtWorkItem è stata eseguita. 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 associata 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 degli elementi 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.
accodati La chiamata a WdfObjectDelete attende il completamento dell'esecuzione dell'elemento di lavoro, quindi l'elemento di lavoro viene pulito
In 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.