Использование объектов таймера
На следующем рисунке показано использование таймера уведомлений для настройки интервала времени ожидания для операции и последующего ожидания, пока другие подпрограммы драйвера обработают запрос ввода-вывода.
Как показано на предыдущем рисунке, драйвер должен предоставить хранилище для объекта таймера, который должен быть инициализирован вызовом KeInitializeTimer с указателем на это хранилище. Драйвер обычно выполняет этот вызов из своей процедуры AddDevice .
В контексте определенного потока, например потока, созданного драйвером, или потока, запрашивающего синхронную операцию ввода-вывода, драйвер может ожидать своего объекта таймера, как показано на предыдущем рисунке:
Поток вызывает KeSetTimer с указателем на объект таймера и заданным значением DueTime , выраженным в единицах 100 наносекунд. Положительное значение для DueTime указывает абсолютное время, в течение которого объект таймера должен быть удален из очереди таймера ядра и установлен в состояние Signaled . Отрицательное значение dueTime указывает интервал относительно текущего системного времени.
Обратите внимание, что поток (или подпрограмма драйвера, выполняющаяся в системном потоке) передает указатель NULL для объекта DPC (показанного ранее на рисунке, иллюстрируя использование объектов таймера и DPC для подпрограммы CustomTimerDpc) при вызове KeSetTimerTimer, если он ожидает объекта таймера вместо постановки в очередь подпрограммы CustomTimerDpc .
Поток вызывает KeWaitForSingleObject с указателем на объект таймера, который переводит поток в состояние ожидания, пока объект таймера находится в очереди таймера ядра.
Срок действия заданного DueTime истекает.
Ядро вывело объект таймера из очереди, присвоит ему состояние Signaled и изменяет состояние потока с ожидания на готово.
Ядро отправляет поток на выполнение, как только будет доступен процессор: то есть ни один другой поток с более высоким приоритетом в настоящее время не находится в состоянии готовности, и нет подпрограмм режима ядра, которые будут выполняться на более высоком IRQL.
Подпрограммы драйвера, которые выполняются в IRQL >= DISPATCH_LEVEL могут инициалировать время ожидания запросов, используя объект таймера со связанным объектом DPC для постановки в очередь подпрограммы CustomTimerDpc, предоставляемой драйвером . Только подпрограммы драйвера, которые выполняются в контексте неarbitrary потока, могут ожидать ненулевого интервала для объекта таймера, как показано на предыдущем рисунке.
Как и любой другой поток, созданный драйвером поток представлен объектом потока ядра, который также является объектом диспетчера. Следовательно, драйверу не нужно, чтобы созданный драйвером поток использовал объект таймера, чтобы добровольно переводить себя в состояние ожидания в течение заданного интервала. Вместо этого поток может вызывать KeDelayExecutionThread с интервалом, предоставленным вызывающим. Дополнительные сведения об этом методе см. в разделе Опрос устройства.
Процедуры DriverEntry, Reinitialize и Unload также выполняются в контексте системного потока, поэтому драйверы могут вызывать KeWaitForSingleObject с инициализированным объектом таймера драйвера или KeDelayExecutionThread во время инициализации или выгрузки. Драйвер устройства может вызывать KeStallExecutionProcessor в течение очень короткого интервала (предпочтительно менее 50 микросекунд), если ему необходимо дождаться обновления состояния устройства во время его инициализации.
Однако драйверы более высокого уровня обычно используют другой механизм синхронизации в подпрограммах DriverEntry и Reinitialize вместо использования объекта таймера. Драйверы более высокого уровня всегда должны быть рассчитаны на слой по любому низкоуровневому драйверу определенного типа или типа устройства. Таким образом, драйвер более высокого уровня, как правило, медленно загружается, если он ожидает объекта таймера или вызывает KeDelayExecutionThread, так как такой драйвер должен ждать достаточно долго, чтобы вместить самое медленное устройство, поддерживающее его. Обратите внимание, что "безопасный", но минимальный интервал для такого ожидания очень трудно определить.
Аналогичным образом драйверы PnP не должны ждать выполнения других действий, а должны использовать механизм уведомления диспетчера PnP.