Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Следующие факторы усложняют код драйвера, который обрабатывает аппаратные прерывания в многопроцессорных системах:
Каждый раз, когда устройство прерывает работу, оно предоставляет сведения о прерывании, которые являются переменными, так как они могут быть перезаписаны при следующем прерывании устройства.
Устройства вызывают прерывания на относительно высоких уровнях IRQL, и их подпрограммы обслуживания прерываний (ISR) могут прервать выполнение другого кода драйвера.
Для прерываний DIRQL ISR должен выполняться на DIRQL при удержании блокировки спин, предоставленной драйвером, чтобы ISR мог предотвратить дополнительные прерывания, сохраняя изменчивую информацию. DIRQL предотвращает прерывание текущим процессором, а спин-блокировка предотвращает прерывание другим процессором.
Выполнение ISR должно происходить быстро, так как устройство не может прерывать выполнение ISR. Длительное время выполнения ISR может замедлить работу системы или, возможно, привести к потере данных.
Подпрограмма ISR и подпрограмма вызова отложенной процедуры (DPC) обычно должны получить доступ к области хранения, где ISR сохраняет изменяемые данные устройства. Эти подпрограммы должны синхронизироваться друг с другом, чтобы они не обращались к зоне хранения одновременно.
Из-за всех этих факторов при написании кода драйвера, обрабатывающего прерывания, необходимо использовать следующие правила:
Только функция обратного вызова EvtInterruptIsr обращается к изменчивым данным прерываний, таким как регистры устройств, содержащие информацию о прерывании.
Функция обратного вызова EvtInterruptIsr должна переместить переменные данные в буфер данных прерывания, определенный драйвером, к которому функция обратного вызова EvtInterruptDpc, функция обратного вызова EvtInterruptWorkItem или несколько функций обратного вызова EvtDpcFunc могут получить доступ.
Если драйвер предоставляет функции обратного вызова EvtInterruptDpc или EvtInterruptWorkItem для своих объектов прерывания, данные прерывания лучше всего следует хранить в пространстве контекста объекта прерывания. Функции обратного вызова для объекта прерывания могут осуществлять доступ к пространству контекста объекта с помощью предоставленного им дескриптора объекта.
Если ваш драйвер предоставляет несколько функций обратного вызова EvtDpcFunc для каждой функции обратного вызова EvtInterruptIsr, вы можете хранить информацию о прерываниях в контекстном пространстве каждого объекта DPC.
Весь код драйвера, который обращается к буферу данных прерывания, должен быть синхронизирован таким образом, чтобы в одно время только одна подпрограмма обращается к данным.
Для объектов прерывания DIRQL функция обратного вызова EvtInterruptIsr обращается к этому буферу данных на уровне IRQL = DIRQL, удерживая спин-блокировку, предоставленную драйвером объекта прерывания. Поэтому все подпрограммы, которые обращаются к буферу, должны выполняться на DIRQL, держа спин-блокировку. (Как правило, функция обратного вызова EvtInterruptDpc или EvtDpcFunc является единственной другой процедурой, которая должна получить доступ к буферу.)
Все подпрограммы, обращаюющиеся к буферу данных прерывания, за исключением функции обратного вызова EvtInterruptIsr, должны выполнять одно из следующих действий:
- Вызовите WdfInterruptSynchronize, чтобы запланировать функцию обратного вызова EvtInterruptSynchronize, которая обращается к буферу данных прерывания.
- Поместите код, обращающийся к буферу данных прерывания, между вызовами WdfInterruptAcquireLock и WdfInterruptReleaseLock.
Оба этих метода позволяют функции EvtInterruptDpc или EvtDpcFunc получить доступ к данным прерывания на DIRQL, удерживая спин-блокировку прерывания. DIRQL предотвращает прерывание текущим процессором, а спин-блокировка предотвращает прерывание другим процессором.
Если ваше устройство поддерживает несколько векторов прерываний или сообщений, и вы хотите синхронизировать обработку этих прерываний вашим драйвером, можно назначить одну спин-блокировку нескольким объектам прерываний DIRQL. Фреймворк определяет самый высокий DIRQL из набора прерываний и всегда захватывает блокировку спина на этом DIRQL, чтобы синхронизированный код не мог быть прерван векторами прерываний или сообщениями из этого набора.
Для объектов прерываний пассивного уровняплатформа получает блокировку прерываний пассивного уровня перед вызовом функции обратного вызова драйвера EvtInterruptIsr при IRQL = PASSIVE_LEVEL. В результате все подпрограммы, обращаюющиеся к буферу, должны получать блокировку прерывания или внутренне синхронизировать доступ к буферу. Как правило, функция обратного вызова прерывания EvtInterruptWorkItem является единственной другой подпрограммой, которая обращается к буферу. Сведения о получении блокировки прерываний из функции обратного вызова EvtInterruptWorkItem см. в разделе "Примечания" этой страницы.
Вы также можете синхронизировать обработку драйвера нескольких векторов прерываний, назначив одну блокировку ожидания нескольким объектам прерываний пассивного уровня.
Если некоторый код, обрабатывающий прерывания DIRQL, должен выполняться на уровне IRQL = PASSIVE_LEVEL, функция обратного вызова EvtInterruptDpc или EvtDpcFunc может создать один или несколько рабочих элементов , чтобы код выполнялся в виде функций обратного вызова EvtWorkItem.
Кроме того, в KMDF версии 1.11 и более поздних версиях драйвер может запросить элемент обработки прерывания с помощью вызова WdfInterruptQueueWorkItemForIsr. (Помните, что функция обратного вызовадрайвераEvtInterruptIsr может вызывать WdfInterruptQueueWorkItemForIsr или WdfInterruptQueueDpcForIsr, но не обе.)
Если важно синхронизировать функции обратного вызова драйвера EvtInterruptDpc и EvtDpcFunc друг с другом, а также с другими функциями обратного вызова, связанными с устройством, драйвер может задать элемент AutomaticSerialization значением TRUE в структуре WDF_INTERRUPT_CONFIG прерывания и структуре объекта DPC WDF_DPC_CONFIG. Кроме того, драйвер может использовать спинлоки фреймворка . (Установка члена AutomaticSerialization в значение TRUE не синхронизирует функцию обратного вызова EvtInterruptIsr с другими функциями обратного вызова. Используйте WdfInterruptSynchronize или WdfInterruptAcquireLock для синхронизации функции обратного вызова EvtInterruptIsr, как описано ранее в этом разделе.)
Дополнительные сведения о синхронизации подпрограмм драйверов см. в техниках синхронизации для драйверов, основанных на каркасе.