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


Примеры синхронизации

В следующих примерах показано, что минидрайверу необходимо сделать в отношении синхронизации, и примеры того, когда синхронизация не должна использоваться:

  • Пример 1: Минидрайвер с функционирующим ISR

    Если синхронизация класса потоков включена, все точки входа минидрайвера вызываются при повышенном IRQL с помощью KeSynchronizeExecution, что означает, что уровень IRQ адаптера и все более низкие уровни IRQ маскируются при выполнении кода минидрайвера. Поэтому очень важно, чтобы минидрайвер выполнял лишь небольшое количество работы в этом режиме.

    Мини-драйвер не должен запускать код, который обычно занимает более 10–20 микросекунд на повышенном уровне IRQL. Если вы используете отладочную сборку stream.sys, класс потока регистрирует время, затраченное на поднятый IRQL, и утверждает, что драйвер тратит слишком много времени там. Если минидрайвер просто должен программировать аппаратные регистры DMA для запроса или просто считывать порты в своей ISR, то обычно приемлемо выполнять всю обработку при повышенном уровне IRQL.

    Если минидрайвер должен выполнять обработку, которая занимает более нескольких микросекунд, например минидрайвер, который передает данные через PIO, минидрайвер должен использовать StreamClassCallAtNewPriority для планирования обратного вызова уровня DISPATCH_LEVEL. В обратном вызове минидрайвер может занять от 1/2 до 1 миллисекунды, чтобы обработать данные. Важно помнить, что при этом режиме обратный вызов DISPATCH_LEVEL не синхронизирован с ISR.

    Это отсутствие синхронизации не является проблемой, если оборудование остается стабильным, когда минидрайвер обращается к ресурсам (например, портам или очереди) как во время обратного вызова, так и в прерываниях ISR. Но если нестабильность может быть проблемой, минидрайвер должен использовать StreamClassCallAtNewPriority, чтобы запланировать обратный вызов с высоким приоритетом, при котором диспетчеризация DISPATCH_LEVEL касается ресурсов, которые разделяют доступ с ресурсами, используемыми ISR.

    Обратите внимание, что обратный вызов с высоким приоритетом эквивалентен вызову KeSynchronizeExecution. KeSynchronizeExecution требует от минидрайвера ссылаться на несколько параметров, которые StreamClassCallAtNewPriority не использует, но в целом обе функции приводят к одному и тому же поведению.

    Если минидрайверу только иногда нужно выполнять код, который занимает более 1/2 до 1 миллисекунды, или иногда нужно вызывать службы на уровне PASSIVE_LEVEL (например, во время инициализации), то для получения рабочего потока на уровне PASSIVE_LEVEL можно использовать параметр StreamClassCallAtNewPriority с НИЗКИМ приоритетом. Обратите внимание, что обратный вызов с низким приоритетом не синхронизирован ни с чем, и минидрайвер может получать новые запросы (при условии, что ожидается параметр ReadyForNextRequest NotificationType) или вызов ISR во время выполнения обратного вызова с низким приоритетом.

  • Пример 2. Минидрайвер без ISR

    Если синхронизация класса потоков активирована, точки входа минидрайвера вызываются на уровне DISPATCH_LEVEL. Минидрайвер может выполнять обработку от 0,5 до 1 миллисекунды, не требуя настройки приоритета. Если минидрайверу требуется время от времени выполнить код, который занимает более 1/2 миллисекунды, или вызвать службы на уровне PASSIVE_LEVEL (например, во время инициализации), то StreamClassCallAtNewPriority с приоритетом LOW может использоваться для получения рабочего потока на уровне PASSIVE_LEVEL. Обратите внимание, что обратный вызов с низким приоритетом не синхронизирован ни с чем, и минидрайвер может получать новые запросы (при условии, что ожидается уведомление типа ReadyForNextRequest NotificationType), когда выполняется данный обратный вызов.

  • Когда синхронизация класса Streamнедолжна использоваться

    Ниже приведены примеры ситуаций, когда синхронизация классов потоков не должна использоваться. К ним относятся:

    • Если драйверы часто (более 20 процентов запросов, получаемых минидрайвером) необходимо выполнять обработку, которая занимает более 1 миллисекунды, а также часто вызывать службы PASSIVE_LEVEL, такие как службы Microsoft DirectDraw. При использовании отладочной версии stream.sysкласс stream будет утверждать оба этих случая и останавливаться, если они обнаружены с включенной синхронизацией.

    • Если минидрайвер является фильтром без ассоциированного оборудования. Такой минидрайвер должен работать на уровне PASSIVE_LEVEL, так как отсутствует базовое оборудование для синхронизации, и минидрайвер обычно выполняет значительный объем обработки. В этом случае проще выполнять собственную синхронизацию, чем тратить затраты на использование синхронизации класса потоков. При необходимости используйте мьютексы для защиты очередей.

      Ошибки в коде синхронизации часто могут быть трудными для поиска, а в некоторых средах (например, операционных системах на основе NT, работающих в многопроцессорных системах), могут возникать только через много часов стресса. Основываясь на опыте с поставщиками, это не те вещи, которые большинство поставщиков имеют возможность или желание отлаживать. Только авторы драйверов, знакомые с написанием полностью асинхронных драйверов устройств WDM, должны попытаться осуществить собственную синхронизацию.

    • Когда мини-драйвер является драйвером типа шина-на-шина (например, USB или 1394 периферийным драйвером), который не занимается синхронизацией реального оборудования, а только передаёт запросы на нижний уровень на PASSIVE_LEVEL и обычно получает обратные вызовы на уровне DISPATCH_LEVEL.