Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Рабочий элемент — это задача, которую выполняет драйвер в функции обратного вызова события EvtWorkItem. Эти функции выполняются асинхронно на уровне IRQL = PASSIVE_LEVEL в контексте системного рабочего потока.
Драйверы на основе фреймворка обычно используют рабочие элементы, если функция EvtInterruptDpc или EvtDpcFunc, которая выполняется при уровне IRQL = DISPATCH_LEVEL, должна выполнять дополнительную обработку при уровне IRQL = PASSIVE_LEVEL.
Другими словами, драйвер может использовать рабочие элементы, если функция, которая выполняется в IRQL = DISPATCH_LEVEL должна вызывать функцию, которая может вызываться только в IRQL = PASSIVE_LEVEL.
Как правило, функция обратного вызова драйвера EvtInterruptDpc или EvtDpcFunc создает объект рабочего элемента и добавляет его в очередь рабочих элементов системы. Впоследствии рабочий поток системы извлекает объект из очереди и вызывает функцию обратного вызова рабочего элемента EvtWorkItem.
Примеры драйверов, использующих рабочие элементы
примеры драйверов, основанных на фреймворке, которые используют рабочие элементы, включают 1394, AMCC5933, PCIDRV и Toaster.
настройка рабочего элемента
Чтобы настроить рабочий элемент, драйвер должен:
Создайте рабочий элемент.
Драйвер вызывает WdfWorkItemCreate для создания объекта рабочего элемента и определения функции обратного вызова EvtWorkItem, которая будет обрабатывать рабочий элемент.
Храните сведения о рабочем элементе.
Как правило, драйверы используют контекстную память объекта рабочего элемента для хранения сведений о задаче, которую должна выполнять функция обратного вызоваEvtWorkItem. Когда вызывается функция обратного вызова EvtWorkItem, она может получить информацию, получив доступ к этой контекстной памяти. Сведения о выделении и доступе к памяти контекста см. в Контекстное пространство объекта фреймворка.
Добавьте рабочий элемент в очередь рабочих элементов системы.
Драйвер вызывает WdfWorkItemEnqueue, который добавляет рабочий элемент драйвера в очередь рабочих элементов.
Когда драйвер вызывает WdfWorkItemCreate, он должен предоставить дескриптор объекту устройства фреймворка или объекту очереди фреймворка. При удалении этого объекта система также удаляет все существующие рабочие элементы, связанные с объектом. Объект рабочего элемента будет удален, а связанный с ним обратный вызов будет очищен до вызова обратного вызова EvtCleanupCallback родительского объекта .
Дополнительные сведения о правилах очистки иерархии объектов фреймворка см. в разделе Framework Object Life Cycle.
Использование функции обратного вызова Work-Item
После добавления рабочего элемента в очередь рабочих элементов он остается в очереди, пока системный рабочий поток не станет доступным. Рабочий поток системы удаляет рабочий элемент из очереди, а затем вызывает функцию обратного вызова драйвера EvtWorkItem, передав объект рабочего элемента в качестве аргумента.
Как правило, функция обратного вызова EvtWorkItem выполняет следующие действия:
Получает сведения о рабочем элементе, предоставленном драйвером, путем доступа к контекстной памяти объекта рабочего элемента.
Выполняет указанную задачу. При необходимости функция обратного вызова может вызывать WdfWorkItemGetParentObject для определения родительского объекта рабочего элемента.
Вызывает WdfObjectDelete для удаления объекта рабочего элемента или, если драйвер перезапросит рабочий элемент, указывает, что дескриптор рабочего элемента теперь доступен для повторного использования.
Задача, которую выполняет функция обратного вызова каждого рабочего элемента, должна быть относительно короткой. Операционная система предоставляет ограниченное количество рабочих потоков системы, поэтому драйвер может препятствовать производительности системы, если он использует функции обратного вызова рабочих элементов для выполнения временных задач.
создание и удаление рабочих элементов
Драйверы могут использовать один из следующих двух методов для создания и удаления рабочих элементов:
Используйте каждый рабочий элемент один раз: создайте рабочий элемент при необходимости и удалите его сразу после его использования.
Этот метод полезен для драйверов, требующих редкого использования (реже одного раза в минуту) небольшого количества рабочих элементов.
Например, функция обратного вызова EvtInterruptDpc драйвера может вызывать WdfWorkItemCreate, а затем WdfWorkItemEnqueue, а функция обратного вызова рабочего элемента EvtWorkItem может вызывать WdfObjectDelete.
Если ваш драйвер следует этому сценарию, и если его функция обратного вызова EvtInterruptDpc получает значение возврата STATUS_INSUFFICIENT_RESOURCES от WdfWorkItemCreate, драйвер должен быть в состоянии отложить необходимую работу до тех пор, пока системные ресурсы (как правило, память) не станут доступными.
Создайте один или несколько рабочих элементов, которые драйвер повторно ставит в очередь при необходимости.
Этот метод полезен для драйверов, которые часто используют рабочие элементы (чаще, чем один раз в минуту), или если функция обратного вызова драйвера EvtInterruptDpc не может легко обрабатывать возвращаемое значение STATUS_INSUFFICIENT_RESOURCES из WdfWorkItemCreate.
Система не выделяет рабочий поток рабочему элементу, пока драйвер не вызывает WdfWorkItemEnqueue. Таким образом, хотя системные рабочие потоки являются ограниченным ресурсом, создание рабочих элементов при инициализации устройства потребляет небольшой объем памяти, но в остальном не влияет на производительность системы.
Следующие шаги описывают возможный сценарий:
- Функция обратного вызова драйвера EvtDriverDeviceAdd вызывает WdfWorkItemCreate для получения дескриптора рабочего элемента.
- Функция обратного вызова драйвера EvtInterruptDpc создает список действий, которые должна выполнять функция обратного вызова EvtWorkItem, а затем, используя дескриптор из шага 1, вызывает WdfWorkItemEnqueue.
- Функция обратного вызова драйвера EvtWorkItem выполняет список действий и задает флаг, указывающий, что функция обратного вызова запущена.
Впоследствии, при каждом вызове функции обратного вызова драйвера EvtInterruptDpc, необходимо определить, выполнилась ли функция обратного вызова EvtWorkItem. Если функция обратного вызова EvtWorkItem не запущена, функция обратного вызова EvtInterruptDpc не вызывает WdfWorkItemEnqueue, поскольку рабочий элемент все еще в очереди. В этом случае функция обратного вызова EvtInterruptDpc обновляет только список действий для функции обратного вызова EvtWorkItem.
Каждый рабочий элемент связан с устройством или очередью. При удалении связанного устройства или очереди платформа удаляет все связанные рабочие элементы, поэтому при использовании этого метода драйвер не должен вызывать WdfObjectDelete.
Некоторым драйверам может потребоваться вызвать WdfWorkItemFlush, чтобы очистить их рабочие элементы из очереди рабочих элементов. Пример использования WdfWorkItemFlushсм. на справочной странице метода.
Если драйвер вызывает WdfObjectDelete на необработанный рабочий элемент, результат зависит от состояния данного элемента.
Состояние рабочего элемента | Результат |
---|---|
Создано, но не поставлено в очередь | Рабочий элемент немедленно очищается. |
В очереди | Вызов WdfObjectDelete ожидает завершения выполнения рабочего элемента, а затем рабочий элемент очищается |
Выполнение | Если драйвер вызывает WdfObjectDelete из EvtWorkItem (в одном потоке), WdfObjectDelete возвращается немедленно. После завершения EvtWorkItem рабочий элемент будет очищен. В противном случае WdfObjectDelete ожидает завершения EvtWorkItem. |