Объекты семафора

Любой драйвер может использовать объект семафора для синхронизации операций между потоками, созданными драйвером, и другими подпрограммами драйвера. Например, выделенный драйвером поток может переводить себя в состояние ожидания, если отсутствуют невыполненные запросы ввода-вывода для драйвера, а подпрограммы диспетчеризации драйвера могут задать для семафора состояние Signaled сразу после того, как они помещают IRP в очередь.

Подпрограммы диспетчеризации драйверов самого высокого уровня, которые выполняются в контексте потока, запрашивающего операцию ввода-вывода, могут использовать семафор для защиты ресурса, совместно используемого подпрограммами диспетчеризации. Низкоуровневые подпрограммы диспетчеризации драйверов для синхронных операций ввода-вывода также могут использовать семафор для защиты ресурса, совместно используемого этим подмножеством подпрограмм диспетчеризации, или с помощью потока, созданного драйвером.

Любой драйвер, использующий объект семафора, должен вызвать KeInitializeSemaphore , прежде чем ожидать или отпустить семафор. На следующем рисунке показано, как драйвер с потоком может использовать объект семафора.

схема, иллюстрирующая ожидание объекта семафора.

Как показано на предыдущем рисунке, такой драйвер должен предоставить хранилище для объекта семафора, который должен быть резидентом. Драйвер может использовать расширение устройства созданного драйвером объекта устройства, расширение контроллера, если он использует объект контроллера, или пул без паха, выделенный драйвером.

Когда подпрограмма AddDevice драйвера вызывает KeInitializeSemaphore, она должна передать указатель на резидентное хранилище драйвера для объекта семафора. Кроме того, вызывающий объект должен указать count для объекта семафора, как показано на предыдущем рисунке, который определяет его начальное состояние (ненулевое значение для Signaled).

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

  • Ограничение = 1

    Если для этого семафора задано состояние Signaled, один поток, ожидающий, пока семафору будет присвоено состояние Signaled, становится допустимым для выполнения и может получить доступ к ресурсу, защищенному семафором.

    Этот тип семафора также называется двоичным семафором , так как поток имеет или не имеет монопольного доступа к ресурсу, защищенному семафором.

  • Ограничение > 1

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

    Этот тип семафора называется семафором подсчета , так как подпрограмма, устанавливающая семафор в состояние Signaled, также указывает, сколько ожидающих потоков может изменить состояние ожидания на готово. Число таких ожидающих потоков может быть ограничением , установленным при инициализации семафора, или некоторым числом, меньшим, чем это предустановленное ограничение.

Несколько драйверов устройств или промежуточных драйверов имеют один поток, созданный драйвером; еще меньшее количество потоков, которые могут ожидать получения или освобождения семафора. Немногие системные драйверы используют объекты семафора, а еще меньше — двоичный семафор. Хотя двоичный семафор может показаться похожим по функциональности на объект мьютекса, двоичный семафор не обеспечивает встроенную защиту от взаимоблокировок, которая имеется в объекте мьютекса для системных потоков, работающих на компьютерах SMP.

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

  1. Поток вызывает KeWaitForSingleObject с указателем на хранилище, предоставленное драйвером для инициализированного объекта семафора, чтобы перейти в состояние ожидания.

  2. Начинают поступать irp, требующие операций ввода-вывода устройства. Подпрограммы диспетчеризации драйвера вставляют каждую из таких IRP в заблокированную очередь под управлением spin-lock и вызывают KeReleaseSemaphore с указателем на объект семафора, определяемого драйвером повышения приоритета для потока (приращение, как показано на предыдущем рисунке), корректировку 1, которая добавляется к счетчику семафора по мере постановки в очередь каждого IRP, а для логического ожидания задано значение FALSE. Ненулевое число семафоров устанавливает для объекта семафора состояние Signaled, тем самым изменяя состояние ожидающего потока на готово.

  3. Ядро отправляет поток на выполнение, как только будет доступен процессор: то есть ни один другой поток с более высоким приоритетом в настоящее время не находится в состоянии готовности, и нет подпрограмм режима ядра, которые будут выполняться на более высоком IRQL.

    Поток удаляет IRP из заблокированной очереди под управлением spin-lock, передает его другим подпрограммам драйвера для дальнейшей обработки и снова вызывает KeWaitForSingleObject . Если для семафора по-прежнему задано состояние Signaled (то есть его значение Count остается ненулевым, что указывает на то, что в очереди с блокировкой драйвера находится больше irP), ядро снова изменит состояние потока с ожидания на готово.

    При использовании семафора подсчета таким образом такой поток драйвера "знает", что существует IRP, который будет удален из заблокированной очереди при каждом запуске этого потока.

Сведения об управлении IRQL при вызове KeReleaseSemaphore см. в разделе Примечания статьи KeReleaseSemaphore.

Любая стандартная подпрограмма драйвера, которая выполняется в IRQL больше PASSIVE_LEVEL не может ждать ненулевого интервала для каких-либо объектов диспетчера без отключения системы; Дополнительные сведения см. в разделе Объекты диспетчера ядра . Однако такая подпрограмма может вызывать KeReleaseSemaphore при выполнении на IRQL меньше или равно DISPATCH_LEVEL.

Сводку по спискам IRQL, в которых выполняются стандартные подпрограммы драйвера, см. в разделе Управление приоритетами оборудования. Требования IRQL для конкретной процедуры поддержки см. на странице справочника по подпрограмме.