Рейтинговые книги
Читем онлайн 3.Внутреннее устройство Windows (гл. 8-11) - Марк Руссинович

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 16 17 18 19 20 21 22 23 24 ... 45

И последнее замечание о завершении ввода-вывода. Функции асинхронного ввода-вывода ReadFileEx и WriteFileEx принимают в качестве параметра APC пользовательского режима. Если поток передаст этот параметр, то на последнем этапе диспетчер ввода-вывода направит соответствующий APC в очередь данного потока. Эта функциональность позволяет вызывающему потоку указывать процедуру, которую нужно вызывать после завершения или отмены запроса ввода-вывода. Такие APC выполняются в контексте вызывающего потока и доставляются, только если поток переходит в состояние «тревожного» ожидания (как, например, при вызове Windows-функции SleepEx, WaitForSingleObjectEx или WaitForMultipleObjectsEx).

Синхронизация

Драйверы должны синхронизировать свое обращение к глобальным данным и регистрам устройств в силу двух причин.

Выполнение драйвера может быть прервано из-за вытеснения потоками с более высоким приоритетом, по истечении выделенного кванта процессорного времени, а также из-за генерации прерывания.

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

Без синхронизации данные могут быть повреждены. Например, код драйвера устройства выполняется при IRQL уровня «passive». Какая-то программа инициирует операцию ввода-вывода, в результате чего возникает аппаратное прерывание. Оно прерывает выполнение кода драйвера и активизирует его ISR. Если в этот момент драйвер изменял какие-либо данные, которые модифицирует и ISR (например, регистры устройства, память из кучи или статические данные), они могут быть повреждены после выполнения ISR. Эту проблему демонстрирует рис. 9-15.

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

Ядро Windows предоставляет специальную синхронизирующую процедуру KeSynchronizeExecution, которую драйверы устройств должны вызывать при доступе к данным, разделяемым с ISR. Эта процедура не допускает выполнения ISR, пока драйвер обращается к общим данным. B однопроцессорных системах перед обновлением общих структур данных она повышает IRQL до уровня, сопоставленного с ISR. Ho в многопроцессорных системах эта методика не гарантирует полной блокировки, так как код драйвера может выполняться на двух и более процессорах одновременно. Поэтому в многопроцессорных системах применяется другой механизм — спин-блокировка (см. раздел «Синхронизация ядра» главы 3). Драйвер также может использовать KeAcquireInterruptSpinLock для прямого доступа к спин-блокировке объекта прерывания, хотя вариант синхронизации с ISR через KeSynchronizeExecution обычно работает быстрее.

Теперь вы понимаете, что не только ISR требуют особого внимания: любые данные, используемые драйвером устройства, могут быть объектом доступа со стороны другой части того же драйвера, выполняемой на другом процессоре. Так что синхронизация доступа к любым глобальным или разделяемым данным (и обращений к самому физическому устройству) критически важна для кода драйвера устройства. Если ISR тоже обращается к этим данным, драйвер устройства должен вызывать KeSynchronizeExecution в ином случае драйвер устройства может использовать стандартные спин-блокировки ядра.

Запрос ввода-вывода к многоуровневому драйверу

B предыдущем разделе мы рассмотрели обработку запроса на ввод-вывод, адресованного простому устройству, которое управляется единственным драйвером устройства. Обработка ввода-вывода для устройств, имеющих дело с файлами, или запросов к другим многоуровневым драйверам во многом аналогична. Конечно, основное отличие в том, что появляется один или несколько дополнительных уровней обработки.

Прохождение запроса на асинхронный ввод-вывод через многоуровневые драйверы показано на рис. 9-l6. Данный пример относится к диску, управляемому файловой системой.

И вновь диспетчер ввода-вывода получает запрос, создает IRP для его представления, но на этот раз передает пакет драйверу файловой системы. C этого момента драйвер файловой системы в основном и управляет операцией ввода-вывода. B зависимости от типа запроса файловая система посылает драйверу диска тот же IRP или генерирует дополнительные IRP и передает их этому драйверу по отдельности.

ЭКСПЕРИМЕНТ: просмотр стека устройства

Команда !devstack отладчика ядра показывает стек устройства, содержащий многоуровневые объекты «устройство», сопоставленные с указанным объектом «устройство». B данном примере выводится стек устройства для объекта «устройство» devicekeyboardclass0, который принадлежит драйверу класса клавиатур:

Строка для KeyboardClass0 выделяется префиксом «›». Элементы над этой строкой относятся к драйверам, размещаемым над драйвером класса клавиатур, а элементы под выделенной строкой — к драйверам, расположенным ниже драйвера класса клавиатур. B целом, IRP передаются по стеку сверху вниз.

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

Для поддержки использования несколькими драйверами IRP содержит набор блоков стека (не путать со стеком потока). Эти блоки данных — по одному на каждый вызываемый драйвер — хранят информацию, необходимую каждому драйверу для обработки своей части запроса (например, номер функции, параметры, сведения о контексте драйвера). Как показано на рис. 9-l6, по мере передачи IRP от одного драйвера другому заполняются дополнительные блоки стека. IRP можно считать аналогом стека в отношении добавления и удаления данных. Ho IRP не сопоставляется ни с каким процессом, и его размер фиксирован. B самом начале операции ввода-вывода диспетчер ввода-вывода выделяет память для IRP в одном из ассоциативных списков IRP или в пуле неподкачиваемой памяти.

ЭКСПЕРИМЕНТ: исследуем IRP

B этом эксперименте вы найдете незавершенные IRP в системе и определите тип IRP, устройство, которому он адресован, драйвер, управляющий этим устройством, поток, выдавший IRP, и процесс, к которому относится данный поток.

B любой момент в системе есть хотя бы несколько незавершенных IRR Это вызвано тем, что существует много устройств, которым приложения могут посылать IRP, а драйвер обрабатывает запрос только при возникновении определенного события, скажем, при появлении данных. Один из примеров — чтение с сетевого устройства. Увидеть незавершенные IRP в системе позволяет команда !irpfind отладчика ядра:

Строка, выделенная в выводе, описывает IRP, адресованный драйверу Kbdclass, так что этот IRP скорее всего был выдан потоком необработанного ввода для подсистемы Windows, принимающим ввод с клавиатуры. Изучение IRP с помощью команды !irp показывает следующее:

Активный блок стека (помечаемый префиксом «›», находится в самом низу. Основной номер функции равен 3, что соответствует IRP_MJ_READ.

Следующий шаг — выяснить, какому объекту «устройство» адресован IRP Для этого выполните команду !devobj, указав адрес объекта «устройство», взятый из активного блока стека:

Устройство, которому адресован данный IRP, — KeyboardClassl. Наличие объекта «устройство», принадлежащего драйверу Termdd, сообщает, что этот объект представляет ввод от клиента службы терминалов, а не с физической клавиатуры. (Листинг был получен в системе с Windows XP.)

Детальные сведения о потоке и процессе, выдавшем этот IRP, можно просмотреть командами !thread и /process:

Найдя этот поток в Process Explorer (www.sysinternals.com) на вкладке Threads окна свойств для Csrss.exe, вы убедитесь, что, судя по именам функций в его стеке, он действительно является потоком необработанного ввода (raw input thread) для подсистемы Windows.

После того как драйвер диска завершает передачу данных, диск генерирует прерывание, и ввод-вывод завершается (рис. 9-17).

Рис. 9-17. Завершение обработки запроса на ввод-вывод к многоуровневым драйверам

B качестве альтернативы повторному использованию единственного IRP файловая система может создать группу сопоставленных IRP (associated IRPs), которые будут обрабатываться параллельно. Например, если данные, которые нужно считать из файла, разбросаны по всему диску, драйвер файловой системы может создать несколько IRP, каждый из которых инициирует чтение данных из отдельного сектора. Этот случай иллюстрирует рис. 9-18.

1 ... 16 17 18 19 20 21 22 23 24 ... 45
На этой странице вы можете бесплатно читать книгу 3.Внутреннее устройство Windows (гл. 8-11) - Марк Руссинович бесплатно.
Похожие на 3.Внутреннее устройство Windows (гл. 8-11) - Марк Руссинович книги

Оставить комментарий