Добавлен: 29.10.2018
Просмотров: 48015
Скачиваний: 190
976
Глава 11. Изучение конкретных примеров: Windows 8
Каталог
Содержимое
\Arcname
Имена разделов, обнаруженных начальным загрузчиком
\NLS
Объекты поддержки национальных языков
\FileSystem
Объекты драйверов файловых систем и объекты распознавателей
файловых систем
\Security
Принадлежащие системе безопасности объекты
\KnownDLLs
Основные совместно используемые библиотеки, которые рано откры-
ваются и остаются открытыми
Странно названный каталог
\??
содержит имена всех устройств в стиле MS-DOS, такие
как
А:
(для флоппи-диска) и
С:
(для первого жесткого диска). Эти имена фактически
являются символическими ссылками на каталог
\Device
, где и находятся объекты
устройств. Имя
\??
было выбрано для того, чтобы оно было первым по алфавиту (для
ускорения поиска тех маршрутов, которые начинаются с буквы диска). Содержимое
других каталогов объектов должно быть понятно без пояснений.
Как описывалось ранее, диспетчер объектов поддерживает в каждом объекте отдельный
счетчик описателей. Этот счетчик никогда не бывает больше, чем счетчик указателей
со ссылками, поскольку каждый допустимый описатель имеет указатель (на объект)
со ссылкой в своем элементе таблицы описателей. Отдельный счетчик описателей не-
обходим, поскольку многим типам объектов может понадобиться очистка состояния
после исчезновения последней ссылки пользовательского режима (даже если они еще
не готовы к удалению из памяти).
Пример — файловые объекты, которые представляют собой экземпляр открытого
файла. В Windows файл можно открыть для монопольного доступа. Когда последний
описатель файлового объекта закрывается, важно убрать монопольный доступ именно
в этот момент, а не ждать, пока исчезнут вспомогательные ссылки ядра (например,
оставшиеся после последнего сброса данных из памяти). В противном случае закрытие
и повторное открытие файла из пользовательского режима может и не сработать (по-
скольку файл будет продолжать находиться в состоянии использования).
Несмотря на то что диспетчер объектов имеет все механизмы для управления жизнен-
ным циклом объектов внутри ядра, ни интерфейсы NT API, ни Win32 API не предо-
ставляют ссылочного механизма для работы с описателями в нескольких параллельных
потоках пользовательского режима. Таким образом, во многих многопоточных прило-
жениях создаются условия гонки и ошибки, когда они закрывают описатель в одном
потоке еще до того, как завершится работа с ним в другом потоке; либо описатель
закрывается много раз; либо закрывают такой описатель, который еще используется
в другом потоке, и используют его для ссылки на другой объект.
Возможно, Windows API надо было спроектировать таким образом, чтобы для каж-
дого типа объектов требовалось свое API закрытия объекта (а не просто одна общая
операция NtClose). Это по крайней мере снизило бы частоту возникновения ошибок
из-за того, что потоки пользовательского режима закрывают не те описатели. Другим
решением могло бы быть встраивание поля последовательного номера в каждый опи-
сатель (в дополнение к индексу таблицы описателей).
Таблица 11.9 (продолжение)
11.3. Структура системы
977
Для того чтобы помочь авторам приложений находить подобные проблемы в их про-
граммах, Windows имеет верификатор приложений (application verifier), который
разработчики могут скачать с сайта компании Microsoft. Аналогично верификатору
для драйверов (который мы опишем в разделе 11.7), верификатор приложений делает
подробные проверки правил (чтобы помочь программистам отыскать ошибки, кото-
рые могут быть не обнаружены обычным тестированием). Он может также включить
режим упорядочивания FIFO для списка свободных описателей, чтобы описатели не
использовались сразу же повторно (то есть выключить имеющий более высокую про-
изводительность режим LIFO, который обычно используется для таблиц описателей).
Предотвращение быстрого повторного использования описателей меняет ситуацию
использования операцией неправильного описателя на ситуацию использования за-
крытого описателя (что несложно обнаружить).
Объект устройства — это один из самых важных и универсальных объектов режима
ядра исполнительного модуля. Тип указывается диспетчером ввода-вывода, который
наряду с драйверами устройств является основным пользователем объектов устройств.
Объекты устройств тесно связаны с драйверами, причем каждый объект устройства
обычно имеет ссылку на конкретный объект драйвера, который описывает порядок
обращения к процедурам обработки ввода-вывода (для соответствующего устройству
драйвера).
Объекты устройств представляют собой аппаратные устройства, интерфейсы, шины,
а также логические разделы дисков, дисковые тома и даже файловые системы и расши-
рения ядра (наподобие антивирусных фильтров). Многие драйверы устройств имеют
имена, так что к ним можно обращаться без необходимости открывать описатели для
экземпляров устройств (как это делается в UNIX). Чтобы проиллюстрировать ис-
пользование процедуры Parse, мы будем использовать объекты устройств (рис. 11.11).
1. Когда компонент исполнительного уровня (такой, как реализующий собствен-
ный системный вызов NtCreateFile диспетчер ввода-вывода) вызывает ObOpen-
ObjectByName в диспетчере объектов, то он передает маршрут (в кодировке
Unicode) для пространства имен NT (например,
\??\C:\foo\bar
).
2. Диспетчер объектов выполняет поиск по каталогам и символическим ссылкам
и в итоге обнаруживает, что
\??\C:
относится к объекту устройства (типу, опреде-
ленному диспетчером ввода-вывода). Объект устройства — это листовой узел в той
части пространства имен, которой управляет диспетчер объектов.
3. Затем диспетчер объектов вызывает процедуру Parse для этого типа объектов — это
IopParseDevice, реализованная диспетчером ввода-вывода. Она передает не только
указатель на найденный объект устройства (для
С:
), но и остаток строки (
\foo\bar
).
4. Диспетчер ввода-вывода создает IRP (I/O Request Packet — пакет запроса ввода-
вывода), выделяет файловый объект и отправляет запрос в стек устройств ввода-
вывода (определенный объектом устройства, который был найден диспетчером
объектов).
5. IRP передается вниз по стеку ввода-вывода, пока не достигнет того объекта
устройства, который представляет экземпляр файловой системы для
С:
. На всех
стадиях управление передается точке входа в объект драйвера, связанный с объ-
ектом устройства на этом уровне. В данном случае используется точка входа для
операций CREATE, поскольку запрос дан на создание или открытие файла с на-
званием
\foo\bar
данного тома).
978
Глава 11. Изучение конкретных примеров: Windows 8
6. Обнаруженные по мере продвижения IRP к файловой системе объекты устройств
представляют драйверы фильтров файловой системы, которые могут модифи-
цировать операции ввода-вывода до того, как они достигнут объекта устройства
файловой системы. Обычно эти промежуточные устройства представляют собой
расширения системы (наподобие антивирусных фильтров).
7. Объект устройства файловой системы имеет ссылку на объект драйвера файло-
вой системы (например, NTFS). Таким образом, объект драйвера содержит адрес
операции CREATE в NTFS.
8. NTFS заполняет файловый объект и возвращает его диспетчеру ввода-вывода,
который осуществляет возврат вверх по всему стеку устройств (до тех пор, пока
IopParseDevice не вернется в диспетчер объектов — см. раздел 11.8).
9. Диспетчер объектов закончил поиск в пространстве имен. Он получил обратно
инициализированный объект из процедуры Parse (который является файловым
объектом, а не исходным объектом устройства, который он обнаружил). Таким
образом, диспетчер объектов создает описатель для файлового объекта в таблице
описателей текущего процесса и возвращает описатель вызывавшей стороне.
10. Последний шаг — возврат к вызвавшей стороне (в пользовательский режим),
который в данном случае является процедурой CreateFile интерфейса Win32 API.
Она вернет описатель в приложение.
Рис. 11.11. Шаги в диспетчерах ввода-вывода и объектов для создания или открытия файла
и получения описателя файла
Компоненты исполнительного уровня могут создавать новые типы динамически, при
помощи вызова интерфейса ObCreateObjectType диспетчера объектов. Не существует
исчерпывающего списка типов объектов, и от версии к версии они меняются. Неко-
торые из наиболее часто используемых в Windows типов перечислены в табл. 11.10.
Позвольте кратко рассказать об этих объектных типах.
11.3. Структура системы
979
Таблица 11.10. Некоторые часто встречающиеся объектные типы исполнительного
уровня (управляемые диспетчером объектов)
Тип
Описание
Process (процесс)
Пользовательский процесс
Thread (поток)
Поток в процессе
Semaphore (семафор)
Вычислительный семафор, используемый для межпроцессной
синхронизации
Mutex (мьютекс)
Двоичный семафор, используемый для входа в критическую об-
ласть
Event (событие)
Объект синхронизации с постоянным состоянием (сигнализиро-
ванным или нет)
ALPC Port (Порт ALPC)
Механизм для передачи сообщений между процессами
Timer (таймер)
Объект, который разрешает потоку бездействовать в течение
фиксированного периода времени
Queue (очередь)
Объект, который используется для уведомления о завершении
асинхронного ввода-вывода
Open file (открытый файл)
Объект, который связан с открытым файлом
Access token (маркер
доступа)
Дескриптор безопасности для некоего объекта
Profile (профиль)
Структура данных, используемая для профилирования использо-
вания процессора
Section (сегмент)
Объект, который используется для представления отображаемых
файлов
Key (ключ)
Ключ реестра (используется для прикрепления реестра к про-
странству имен диспетчера объектов)
Object directory (каталог
объектов)
Каталог для группировки объектов в диспетчере объектов
Symbolic link (символиче-
ская ссылка)
Ссылается на другой объект диспетчера объектов при помощи
маршрута
Device (устройство)
Объект устройства ввода-вывода для физического устройства,
шины, драйвера или экземпляра тома
Device driver (драйвер
устройства)
Каждый загруженный драйвер устройства имеет свой объект
Процесс и поток являются очевидными. Есть один объект для каждого процесса
и каждого потока, который хранит главные свойства (необходимые для управления
процессом или потоком). Следующие три объекта (семафор, мьютекс и событие) от-
носятся к межпроцессной синхронизации. Семафоры и мьютексы работают как обычно,
но имеют разные дополнительные возможности (например, максимальные значения
и тайм-ауты). События могут находиться в одном из двух состояний: сигнализирован-
ном или несигнализированном. Если поток ждет события, которое находится в сигна-
лизированном состоянии, то он немедленно освобождается. Если событие находится
в несигнализированном состоянии, то он блокируется до того момента, когда какой-то
другой поток просигнализирует об этом событии, после чего произойдет освобождение
либо всех заблокированных потоков (для событий уведомления), либо только первого
980
Глава 11. Изучение конкретных примеров: Windows 8
заблокированного потока (для событий синхронизации). Событие может быть также
настроено таким образом, что после успешного получения сигнала оно автоматически
перейдет в несигнализированное состояние (а не останется в сигнализированном со-
стоянии).
Объекты порта, таймера и очереди также относятся к обмену и синхронизации. Пор-
ты — это каналы между процессами (для обмена сообщениями LPC). Таймеры предо-
ставляют способ блокирования на определенный интервал времени. Очереди (извест-
ные внутри системы как KQUEUES) используются для уведомления потоков о том,
что ранее начатая операция асинхронного ввода-вывода завершилась, или о том, что
в порту ждет сообщение. Очереди созданы для управления уровнем параллелизма
в приложении и используются в высокопроизводительных многопроцессорных при-
ложениях, например таких, как серверы систем управления базами данных.
Открытые файловые объекты создаются при открытии файла. Неоткрытые файлы не
имеют объектов, которыми управляет диспетчер объектов. Маркеры доступа — это объ-
екты безопасности. Они идентифицируют пользователя и рассказывают о том, какие
специальные привилегии этот пользователь имеет (если они есть). Профили — это
структуры, которые используются для хранения периодических отсчетов программного
счетчика работающего потока (чтобы выяснить, где программа проводит свое время).
Сегменты используются для представления объектов памяти, которые приложения
могут попросить у диспетчера памяти отобразить на свое адресное пространство.
Они хранят сведения о сегменте файла (или файла подкачки), который представляет
страницы объекта памяти (когда они находятся на диске). Ключи представляют для
пространства имен реестра точку монтирования в пространстве имен диспетчера объ-
ектов. Обычно имеется только один объект ключа (с названием \REGISTRY), который
соединяет названия ключей реестра и их значения с пространством имен NT.
Каталоги объектов и символические ссылки являются полностью локальными для
той части пространства имен NT, которая управляется диспетчером объектов. Они
похожи на свои аналоги в файловой системе: каталоги позволяют собрать вместе
связанные между собой объекты. Символические ссылки позволяют имени из одной
части пространства имен объектов ссылаться на объект в другой части пространства
имен объектов.
Каждое известное операционной системе устройство имеет один (или несколько)
объектов устройств, которые содержат информацию о нем и используются системой
для ссылок на устройство. И наконец, каждый драйвер устройства (который был за-
гружен) имеет объект драйвера в пространстве объектов. Объекты драйвера совместно
используются всеми объектами устройств, которые представляют собой экземпляры
устройств, управляемых этими драйверами.
Прочие объекты (не указанные в таблице) служат более специализированным целям
(взаимодействие с транзакциями ядра, пул рабочих потоков Win32).
11.3.4. Подсистемы, DLL и службы
пользовательского режима
Возвращаясь к рис. 11.2, мы видим, что операционная система Windows состоит из
компонентов режима ядра и компонентов пользовательского режима. Мы закончили
обзор компонентов режима ядра — пришло время рассмотреть компоненты пользо-