Наверх Системное программирование
Предыдущий раздел Оглавление Следующий раздел

2.3.3.2. Пространство имен объектов

Процессы могут совместно использовать объекты (один процесс может скопировать описатель объекта в другие процессы). о для этого требуется, чтобы процесс копирования имел описатели других процессов, что во многих ситуациях совершенно непрактично (например, когда совместно использующие объект процессы никак не связаны либо защищены друг от друга). В других случаях важно, чтобы объекты сохранялись даже при отсутствии использования их процессами (это объекты устройств, представляющие физические устройства; либо смонтированные тома; либо объекты, используемые для реализации самого диспетчера объектов и пространства имен NT). Для того чтобы выполнить такие требования совместного использования и хранения, диспетчер объектов позволяет давать произвольным объектам имена в пространстве имен NT (при их создании).

Пространство имен NT иерархическое, его каталоги и символические ссылки реализуются диспетчером объектов. Пространство имен способно расширяться, что позволяет любому типу объектов создать расширения пространства имен. Процедуры, которые могут быть предоставлены для каждого типа объектов при создании, представлены в табл. 2.4.

2.4. Процедуры объекта, предоставляемые при определении нового типа объектов
Процедура Когда вызывается Примечания
Open Для каждого нового описателя Используется редко
Parse Для типов объектов, которые расширяют пространство имен Используется для файлов и ключей реестра
Close При последнем закрывании описателя Очистка видимых побочных эффектов
Delete При последнем снятии косвенности описателя Объект будет в ближайшее время удаляться
Security Получить или установить дескриптор безопасности объекта Защита
OueryName Получить имя объекта Редко используется вне ядра

Процедура Open используется редко, поскольку поведение диспетчера объектов по умолчанию — это именно то, что нужно, и поэтому эта процедура определена как NULL почти для всех типов объектов.

Процедуры Close и Delete представляют собой другие фазы работы с объектом. Когда закрывается последний описатель объекта, могут потребоваться действия по очистке состояния (которые выполняются процедурой Close). Когда из объекта удаляется последняя ссылка на указатель, вызывается процедура Delete, чтобы подготовить объект к удалению и утилизировать его память. Для файловых объектов обе эти процедуры реализованы как обратные вызовы в диспетчер ввода-вывода, как раз и являющийся тем компонентом, который объявил тип объекта «файл». Операции диспетчера объектов приводят к соответствующим операциям ввода-вывода, которые посылаются вниз по связанному с файлом стеку устройств (основную работу делает файловая система).

Процедура Parse используется для открытия или создания объектов (вроде файлов и ключей реестра), которые расширяют пространство имен NT. Когда диспетчер объектов пытается открыть объект по имени и встречает листовой узел в той части пространства имен, которой он управляет, он проверяет, указал ли тип для объекта листового узла процедуру Parse. Если указал, то он вызывает эту процедуру, передавая ей неиспользованную часть маршрута. Например, в файловых объектах листовой узел — это объект устройства, представляющий конкретный том файловой системы. Процедура Parse реализована диспетчером ввода-вывода, в результате она приводит к операции ввода-вывода в файловую систему (для заполнения файлового объекта, который будет ссылаться на открытый экземпляр файла на томе, к которому относится маршрут). Мы изучим этот пример по шагам чуть позже.

Процедура QueryName используется для поиска имени, связанного с объектом. Процедура Security используется для получения, настройки или удаления дескрипторов безопасности объекта. Для большинства объектных типов эта процедура предоставляется как стандартная точка входа в компоненте «монитор безопасности» исполнительного уровня.

Обратите внимание на то, что процедуры, указанные в табл. 2.4, самых полезных операций с объектами, таких как чтение или запись файлов (или сброс и установка семафоров), не выполняют. Вместо этого процедуры диспетчера объектов предоставляют функции, необходимые для правильной настройки доступа к объектам и очистки объектов после прекращения работы с ними. Объекты становятся полезными за счет API-функций, работающих со структурами данных, которые содержатся в объектах. Такие системные вызовы, как NtReadFile и NtWriteFile, используют таблицу описателей процессов, созданную диспетчером объектов для преобразования описателя в ссылочный указатель на исходный объект, например на файловый объект, содержащий данные, необходимые для реализации системных вызовов. Кроме этих обратных вызовов диспетчер объектов предоставляет также набор общих объектных процедур для таких операций, как создание объектов и типов объектов, дублирование описателей, получение указателя со ссылкой из описателя или имени, а также сложение и вычитание количества ссылок на заголовок объекта и NtClose (обобщенная функция, которая закрывает описатели всех типов).

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

Для того чтобы помочь разработчикам приложений находить подобные проблемы в их программах, Windows имеет верификатор приложений, который разработчики могут скачать с сайта компании Microsoft. Аналогично верификатору для драйверов верификатор приложений делает подробные проверки правил. Он может также включить режим упорядочивания FIFO для списка свободных описателей, чтобы описатели не использовались сразу же повторно. Предотвращение быстрого повторного использования описателей меняет ситуацию использования операцией неправильного описателя на ситуацию использования закрытого описателя.

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

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

Компоненты исполнительного уровня могут создавать новые типы динамически, при помощи вызова интерфейса ObCreateObjectType диспетчера объектов. Не существует исчерпывающего списка типов объектов, и от версии к версии они меняются. Некоторые из наиболее часто используемых в Windows типов перечислены в табл. 2.5.

2.5. Некоторые часто встречающиеся объектные типы исполнительного уровня (управляемые диспетчером объектов)
Тип Описание
Process (процесс) Пользовательский процесс
Thread (поток) Поток в процессе
CSemaphore (семафор) Вычислительный семафор, используемый для межпроцессной синхронизации
Mutex (мьютекс) Двоичный семафор, используемый для входа в критическую область
Event (событие) Объект синхронизации с постоянным состоянием (сигнализированным или нет)
ALPC Port (Порт ALPC) Механизм для передачи сообщений между процессами
Timer (таймер) Объект, который разрешает потоку бездействовать в течение фиксированного периода времени
Queue (очередь) Объект, который используется для уведомления о завершении асинхронного ввода-вывода
Open file (открытый файл) Объект, который связан с открытым файлом
Access token (маркер доступа) Дескриптор безопасности для некоего объекта
Profile (профиль) Структура данных, используемая для профилирования использования процессора
Section (сегмент) Объект, который используется для представления отображаемых файлов
Key (ключ) Ключ реестра (используется для прикрепления реестра к пространству имен диспетчера объектов)
Object directory (каталог объектов) МКаталог для группировки объектов в диспетчере объектов
Symbolic link (символическая ссылка) Ссылается на другой объект диспетчера объектов при помощи маршрута
Device (устройство) Объект устройства ввода-вывода для физического устройства, шины, драйвера или экземпляра тома
Device driver (драйвер устройства) Каждый загруженный драйвер устройства имеет свой объект

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

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

Открытые файловые объекты создаются при открытии файла. Неоткрытые файлы не имеют объектов, которыми управляет диспетчер объектов. Маркеры доступа — это объекты безопасности. Они идентифицируют пользователя и рассказывают о том, какие специальные привилегии этот пользователь имеет (если они есть). Профили — это структуры, которые используются для хранения периодических отсчетов программного счетчика работающего потока (чтобы выяснить, где программа проводит свое время).

Сегменты используются для представления объектов памяти, которые приложения могут попросить у диспетчера памяти отобразить на свое адресное пространство. Они хранят сведения о сегменте файла (или файла подкачки), который представляет страницы объекта памяти (когда они находятся на диске). Ключи представляют для пространства имен реестра точку монтирования в пространстве имен диспетчера объектов. Обычно имеется только один объект, который соединяет названия ключей реестра и их значения с пространством имен NT.

Каталоги объектов и символические ссылки являются полностью локальными для той части пространства имен NT, которая управляется диспетчером объектов. Они похожи на свои аналоги в файловой системе: каталоги позволяют собрать вместе связанные между собой объекты. Символические ссылки позволяют имени из одной части пространства имен объектов ссылаться на объект в другой части пространства имен объектов.

Каждое известное операционной системе устройство имеет один (или несколько) объектов устройств, которые содержат информацию о нем и используются системой для ссылок на устройство. И наконец, каждый драйвер устройства (который был загружен) имеет объект драйвера в пространстве объектов. Объекты драйвера совместно используются всеми объектами устройств, которые представляют собой экземпляры устройств, управляемых этими драйверами.

Предыдущий раздел Оглавление Следующий раздел