Использование рабочих элементов платформы

Рабочий элемент — это задача, которую драйвер выполняет в функции обратного вызова события EvtWorkItem. Эти функции выполняются асинхронно в irQL = PASSIVE_LEVEL в контексте системного рабочего потока.

Драйверы на основе платформы обычно используют рабочие элементы, если функция EvtInterruptDpc или EvtDpcFunc , которая выполняется в IRQL = DISPATCH_LEVEL, должна выполнять дополнительную обработку в IRQL = PASSIVE_LEVEL.

Другими словами, драйвер может использовать рабочие элементы, если функция, которая выполняется в IRQL = DISPATCH_LEVEL должна вызывать функцию, которую можно вызывать только в IRQL = PASSIVE_LEVEL.

Как правило, функция обратного вызова EvtInterruptDpc или EvtDpcFunc драйвера создает объект рабочего элемента и добавляет его в очередь рабочих элементов системы. Затем системный рабочий поток удаляет объект из очереди и вызывает функцию обратного вызова EvtWorkItem рабочего элемента.

Примеры драйверов, использующих рабочие элементы

Примеры драйверов на основе платформы , которые используют рабочие элементы, включают 1394, AMCC5933, PCIDRV и Тостер.

Настройка рабочего элемента

Чтобы настроить рабочий элемент, драйвер должен:

  1. Создайте рабочий элемент.

    Драйвер вызывает WdfWorkItemCreate , чтобы создать объект рабочего элемента и определить функцию обратного вызова EvtWorkItem , которая будет обрабатывать рабочий элемент.

  2. Хранение сведений о рабочем элементе.

    Как правило, драйверы используют контекстную память объекта work-item для хранения сведений о задаче, которую должна выполнять функция обратного вызова EvtWorkItem . При вызове функции обратного вызова EvtWorkItem она может получить сведения, получив доступ к этой памяти контекста. Сведения о выделении контекстной памяти и доступе к ней см. в разделе Пространство контекста объектов платформы.

  3. Добавьте рабочий элемент в очередь рабочих элементов системы.

    Драйвер вызывает WdfWorkItemEnqueue, который добавляет рабочий элемент драйвера в очередь рабочих элементов.

Когда драйвер вызывает WdfWorkItemCreate, он должен предоставить дескриптор объекту устройства платформы или объекту очереди платформы. Когда система удаляет этот объект, она также удаляет все существующие рабочие элементы, связанные с объектом . Объект рабочего элемента будет удален, а связанный с ним обратный вызов рабочего элемента будет очищен до вызова обратного вызова EvtCleanupCallback родительского объекта.

Дополнительные сведения о правилах очистки для иерархии объектов платформы см. в разделе Жизненный цикл объектов платформы.

Использование функции обратного вызова Work-Item

После добавления рабочего элемента в очередь рабочих элементов он остается в очереди до тех пор, пока не станет доступен системный рабочий поток. Системный рабочий поток удаляет рабочий элемент из очереди, а затем вызывает функцию обратного вызова EvtWorkItem драйвера, передавая объект work-item в качестве входных данных.

Как правило, функция обратного вызова EvtWorkItem выполняет следующие действия.

  1. Получает предоставленные драйвером сведения о рабочем элементе, получая доступ к контекстной памяти объекта рабочего элемента.

  2. Выполняет указанную задачу. При необходимости функция обратного вызова может вызвать WdfWorkItemGetParentObject , чтобы определить родительский объект рабочего элемента.

  3. Вызывает WdfObjectDelete , чтобы удалить объект рабочего элемента, или, если драйвер повторно отправляет рабочий элемент, указывает, что дескриптор рабочего элемента теперь доступен для повторного использования.

Задача, которую выполняет функция обратного вызова каждого рабочего элемента, должна быть относительно короткой. Операционная система предоставляет ограниченное количество системных рабочих потоков, поэтому драйвер может препятствовать производительности системы, если он использует функции обратного вызова рабочих элементов для выполнения трудоемких задач.

Создание и удаление рабочих элементов

Драйверы могут использовать один из следующих двух способов создания и удаления рабочих элементов:

  • Используйте каждый рабочий элемент один раз: создайте рабочий элемент при необходимости и удалите его сразу после его использования.

    Этот метод полезен для драйверов, которым требуется редкое использование (реже одного раза в минуту) небольшого количества рабочих элементов.

    Например, функция обратного вызова EvtInterruptDpc драйвера может вызывать WdfWorkItemCreate , а затем WdfWorkItemEnqueue, а функция обратного вызова EvtWorkItem рабочего элемента может вызывать WdfObjectDelete.

    Если драйвер следует этому сценарию и его функция обратного вызова EvtInterruptDpc получает STATUS_INSUFFICIENT_RESOURCES возвращаемое значение из WdfWorkItemCreate, драйвер должен иметь возможность отложить требуемую работу до тех пор, пока системные ресурсы (обычно память) не станут доступными.

  • Создайте один или несколько рабочих элементов, которые драйвер повторно отправляет в очередь при необходимости.

    Этот метод полезен для драйверов, которые часто используют рабочие элементы (чаще одного раза в минуту), или если функция обратного вызова EvtInterruptDpc вашего драйвера не может легко обрабатывать STATUS_INSUFFICIENT_RESOURCES возвращаемое значение из WdfWorkItemCreate.

    Система не выделяет рабочий поток для рабочего элемента, пока драйвер не вызовет WdfWorkItemEnqueue. Таким образом, хотя системные рабочие потоки являются ограниченным ресурсом, создание рабочих элементов при инициализации устройства потребляет небольшой объем памяти, но не влияет на производительность системы.

    Ниже описан возможный сценарий.

    1. Функция обратного вызова EvtDriverDeviceAdd драйвера вызывает WdfWorkItemCreate для получения дескриптора рабочего элемента.
    2. Функция обратного вызова EvtInterruptDpc драйвера создает список действий, которые должна выполнять функция обратного вызова EvtWorkItem , а затем вызывает WdfWorkItemEnqueue, используя дескриптор из шага 1.
    3. Функция обратного вызова EvtWorkItem драйвера выполняет список действий и устанавливает флаг, указывающий, что функция обратного вызова запущена.

    Впоследствии при каждом вызове функции обратного вызова EvtInterruptDpc драйвера он должен определить, запущена ли функция обратного вызова EvtWorkItem . Если функция обратного вызова EvtWorkItem не запущена, функция обратного вызова EvtInterruptDpc не вызывает WdfWorkItemEnqueue, так как рабочий элемент по-прежнему находится в очереди. В этом случае функция обратного вызова EvtInterruptDpc обновляет только список действий для функции обратного вызова EvtWorkItem .

    Каждый рабочий элемент связан с устройством или очередью. При удалении связанного устройства или очереди платформа удаляет все связанные рабочие элементы, поэтому при использовании этого метода драйверу не нужно вызывать WdfObjectDelete.

Некоторым драйверам может потребоваться вызвать WdfWorkItemFlush для очистки рабочих элементов из очереди рабочих элементов. Пример использования WdfWorkItemFlush см. на справочной странице метода.

Если драйвер вызывает WdfObjectDelete для выдающегося рабочего элемента, результат зависит от состояния рабочего элемента:

Состояние рабочего элемента Результат
Создано, но не помещено в очередь Рабочий элемент очищается немедленно.
в очереди Вызов WdfObjectDelete ожидает завершения выполнения рабочего элемента, после чего рабочий элемент будет очищен
Выполняется Если драйвер вызывает WdfObjectDelete из EvtWorkItem (в том же потоке), WdfObjectDelete возвращает немедленно. После завершения работы EvtWorkItem рабочий элемент будет очищен. В противном случае WdfObjectDelete ожидает завершения работы EvtWorkItem.