Поделиться через


Синхронизация кода прерывания

Следующие факторы усложняют код драйвера, который обрабатывает аппаратные прерывания в многопроцессорных системах:

  • Каждый раз, когда устройство прерывается, оно предоставляет сведения о конкретном прерывании, которые являются нестабильными, так как они могут быть перезаписаны при следующем прерывании устройства.

  • Устройства прерывают работу с относительно высоким уровнем 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 , должны выполнять одно из следующих действий:

    Оба этих метода позволяют функции 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 прерывания и в структуре WDF_DPC_CONFIG объекта DPC. Кроме того, драйвер может использовать спиновые блокировки платформы. (Установка для элемента AutomaticSerializationзначения TRUE не синхронизирует функцию обратного вызова EvtInterruptIsr с другими функциями обратного вызова. Используйте WdfInterruptSynchronize или WdfInterruptAcquireLock для синхронизации функции обратного вызова EvtInterruptIsr , как описано ранее в этом разделе.)

Дополнительные сведения о синхронизации подпрограмм драйверов см. в разделе Методы синхронизации для драйверов Framework-Based.