Доступ к общим сведениям о состоянии
Используйте следующие общие рекомендации по проектированию и написанию подпрограмм SynchCritSection , поддерживающих состояние.
Для доступа к данным, к которым также обращается ISR, подпрограмма драйвера должна вызвать подпрограмму SynchCritSection . Код некритических разделов может быть прерван. Помните, что недостаточно просто получить спин-блокировку для защиты данных, к которым также обращается ISR, так как ISR выполняются в DIRQL, а получение спин-блокировки (KeAcquireSpinLock) приводит к тому, что IRQL только DISPATCH_LEVEL, что позволяет прерывать вызов ISR на текущем процессоре.
Предоставьте каждой подпрограмме SynchCritSection , которая сохраняет ответственность за сведения о состоянии для дискретного набора переменных состояния. То есть избегайте написания подпрограмм SynchCritSection , которые поддерживают перекрывающиеся сведения о состоянии.
Это предотвращает состязание и, возможно, состояние гонки между подпрограммами SynchCritSection (и ISR), пытающимися получить доступ к одному и тому же состоянию одновременно.
Это также гарантирует, что каждая подпрограмма SynchCritSection возвращает управление как можно быстрее, так как одной подпрограмме SynchCritSection никогда не придется ждать, пока другая подпрограмма обновляет одни и те же сведения о состоянии для возврата управления.
Избегайте написания одной крупной подпрограммы SynchCritSection общего назначения, которая выполняет больше тестирования условий, чтобы определить, что делать, чем на самом деле делать полезную работу. С другой стороны, избегайте использования множества подпрограмм SynchCritSection , которые никогда не выполняют условную инструкцию, так как каждая из них обновляет только один байт сведений о состоянии.
Каждая подпрограмма SynchCritSection должна возвращать управление как можно быстрее, так как выполнение любой подпрограммы SynchCritSection предотвращает выполнение ISR драйвера.
Ниже приведен способ поддержания счетчика таймера в расширении устройства. Предположим, что драйвер использует счетчик, чтобы определить, истекло ли время ожидания операции ввода-вывода. Также предположим, что драйвер не перекрывает операции ввода-вывода.
Подпрограмма StartIo драйвера инициализирует счетчик таймера каким-то начальным значением для каждого запроса ввода-вывода. Затем драйвер добавляет секунду к значению времени ожидания устройства, если его подпрограмма IoTimer только что вернула управление.
IsR драйвера должен установить для этого счетчика таймера значение минус один.
Подпрограмма IoTimer драйвера вызывается один раз в секунду для считывания счетчика времени и определения того, задано ли в ISR значение минус один. В противном случае подпрограмма IoTimer уменьшает счетчик с помощью KeSynchronizeExecution для вызова подпрограммы SynchCritSection_1.
Если счетчик переходит к нулю, указывая, что время ожидания запроса истекло, SynchCritSection_1 подпрограмма вызывает SynchCritSection_2 подпрограмму для программирования операции сброса устройства. Если значение счетчика равно минус 1, то подпрограмма IoTimer просто возвращает значение.
Если подпрограмма DpcForIsr драйвера должна перепрограммировать устройство, чтобы начать операцию частичной передачи, она должна повторно инициализировать счетчик таймера, как это сделала подпрограмма StartIo .
Подпрограмма DpcForIsr также должна использовать KeSynchronizeExecution для вызова SynchCritSection_2 подпрограммы или, возможно, подпрограммы SynchCritSection_3, чтобы запрограммировать устройство для другой операции передачи.
В этом сценарии драйвер имеет несколько подпрограмм SynchCritSection , каждая из которых имеет дискретные, определенные обязанности; один для поддержания счетчика таймера, а другой — для программирования устройства. Каждая подпрограмма SynchCritSection может быстро возвращать управление, так как она выполняет одну дискретную задачу.
Обратите внимание, что драйвер имеет одну подпрограмму SynchCritSection_1, которая вместе с ISR драйвера поддерживает состояние счетчика таймера. Таким образом, между несколькими подпрограммами SynchCritSection и ISR нет состязаний за доступ к счетчику таймера.