Добавлен: 29.10.2018
Просмотров: 48020
Скачиваний: 190
11.3. Структура системы
971
Рис. 11.8. Структура исполнительного объекта, управляемого диспетчером объектов
Выделенная для объектов память берется из одной из двух куч (или пулов) памяти,
поддерживаемых исполнительным уровнем. Это служебные функции (типа malloc) ис-
полнительного уровня, которые позволяют компонентам режима ядра выделять либо
страничную память ядра, либо беcстраничную память ядра. Бесстраничная память тре-
буется для любой структуры данных или объекта режима ядра, к которому необходимо
обратиться с уровня приоритета процессора номер 2 (или более высокого). Это может
быть ISR или DPC (но не АРС), а также сам планировщик потоков. Описателю стра-
ничной ошибки также требуются свои структуры данных, которые должны выделяться
в бесстраничной памяти ядра (во избежание возникновения рекурсии).
Большая часть выделений памяти диспетчером кучи ядра производится при помощи
справочных списков, которые содержат списки (типа LIFO — стек) выделенных блоков
одинакового размера. Эти списки оптимизируются для операций без блокировок, что
улучшает производительность и масштабируемость системы.
Каждый заголовок объекта имеет поле квоты, которое содержит взимаемую с процесса
«плату» за открывание объекта. Квоты используются для того, чтобы пользователь не
использовал слишком много системных ресурсов. Есть отдельные лимиты на бесстра-
ничную память ядра (которая требует выделения как физической памяти, так и вир-
туальных адресов ядра) и страничную память ядра (которая использует виртуальные
адреса ядра). Когда суммарная плата за любой из типов памяти достигает значения
лимита квоты, дальнейшие попытки выделения памяти для данного процесса закан-
чиваются неудачей (из-за недостаточности ресурсов). Квоты используются также дис-
петчером памяти (для управления размером рабочего набора) и диспетчером потоков
(для ограничения степени использования процессора).
Как физическая память, так и виртуальные адреса ядра являются ценными ресурсами.
Когда объект больше не нужен, он должен быть удален и его память и адреса возвра-
щены. Но если объект утилизируется в то время, когда он еще используется, то память
может быть выделена другому объекту, после чего структуры данных, скорее всего,
972
Глава 11. Изучение конкретных примеров: Windows 8
будут повреждены. Это легко может произойти в исполнительном уровне Windows,
поскольку он чрезвычайно многопоточный и реализует много асинхронных операций
(функций, которые делают возврат вызывающей стороне до выполнения работы над
переданными им структурами данных).
Во избежание преждевременного освобождения объектов вследствие состояния гонки
диспетчер объектов реализует механизм подсчета ссылок, а также концепцию указа-
теля
, на который сделана ссылка (referenced pointers). Такой указатель нужен для
доступа к объекту тогда, когда этот объект подвергается опасности удаления. В зави-
симости от соглашений относительно конкретных типов объектов существуют только
определенные моменты времени, когда объект может быть удален другим потоком.
В остальные моменты времени использование блокировок, зависимости между струк-
турами данных и даже тот факт, что ни один из прочих потоков не имеет указателя на
данный объект, смогут предотвратить преждевременное удаление объекта.
Описатели
Ссылки пользовательского режима на объекты режима ядра не могут использовать
указатели, поскольку их трудно проверить. Поэтому объекты режима ядра приходится
именовать как-то иначе (чтобы пользовательский код мог ссылаться на них). Для ссыл-
ки на объекты режима ядра Windows использует описатели (handles, часто также назы-
ваемые дескрипторами). Описатели — это неявные значения, которые конвертируются
диспетчером объектов в ссылки на представляющие объект специфические структуры
данных режима ядра. На рис. 11.9 показана структура данных таблицы дескрипторов,
используемой для трансляции описателей в указатели на объекты. Таблица описате-
лей расширяется путем добавления дополнительных уровней косвенного обращения.
Каждый процесс имеет свою таблицу, включая и системный процесс, который содержит
все потоки ядра, не связанные с процессом пользовательского режима.
Рис. 11.9. Структуры данных таблицы описателей (для минимальной таблицы
для одной страницы с не более чем 512 описателями)
На рис. 11.10 показана таблица описателей с двумя дополнительными уровнями
косвенного обращения (это максимум). Для выполняющегося в режиме ядра кода
иногда бывает удобно иметь возможность использовать описатели (а не указатели со
ссылками). Они называются описателями ядра и специальным образом кодируются,
чтобы их можно было отличить от описателей пользовательского режима. Описатели
ядра хранятся в таблице описателей системных процессов, и к ним нельзя получить
доступ из пользовательского режима. Точно так же как и большая часть виртуального
11.3. Структура системы
973
адресного пространства ядра, системная таблица описателей совместно используется
всеми компонентами ядра вне зависимости от того, какой процесс пользовательского
режима является текущим.
Рис. 11.10. Структуры данных таблицы описателей (для максимальной таблицы
размером до 16 млн описателей)
Пользователи могут создавать новые объекты или открывать уже существующие
объекты (при помощи выполнения вызовов Win32, таких как CreateSemaphore или
OpenSemaphore). Это вызовы библиотечных процедур, которые в итоге приводят
к выполнению соответствующих системных вызовов. Результатом любого успешного
вызова, который создает или открывает объект, является 64-битный элемент таблицы
описателей, который записывается в частную таблицу описателей процесса (в памяти
ядра). Пользователю возвращается 32-битный индекс логического положения описа-
теля в таблице (для использования при последующих вызовах). 64-битный элемент
таблицы описателей в ядре состоит из двух 32-битных слов. Одно слово содержит
29-битный указатель на заголовок объекта. Младшие 3 бита используются как флаги
(например, наследуется ли описатель создаваемыми им процессами). Эти 3 бита ма-
скируются перед переходом по указателю. Второе слово содержит 32-битную маску
привилегий. Она нужна, поскольку проверка прав производится только в момент
создания или открывания объекта. Если процесс имеет на объект только право чтения,
то все прочие биты привилегий в маске будут равны 0, что даст операционной системе
возможность отвергнуть любую другую операцию с объектом (кроме чтения).
Пространство имен объектов
Процессы могут совместно использовать объекты (один процесс может скопировать опи-
сатель объекта в другие процессы). Но для этого требуется, чтобы процесс копирования
имел описатели других процессов, что во многих ситуациях совершенно непрактично
(например, когда совместно использующие объект процессы никак не связаны либо
защищены друг от друга). В других случаях важно, чтобы объекты сохранялись даже
при отсутствии использования их процессами (это объекты устройств, представляю-
щие физические устройства; либо смонтированные тома; либо объекты, используемые
для реализации самого диспетчера объектов и пространства имен NT). Для того чтобы
974
Глава 11. Изучение конкретных примеров: Windows 8
выполнить такие требования совместного использования и хранения, диспетчер объ-
ектов позволяет давать произвольным объектам имена в пространстве имен NT (при их
создании). Однако именно исполнительный компонент (который манипулирует объ-
ектами конкретного типа) определяет, будет ли он предоставлять интерфейсы, которые
поддерживают использование средств именования диспетчера объектов.
Пространство имен NT иерархическое, его каталоги и символические ссылки реализу-
ются диспетчером объектов. Пространство имен способно расширяться, что позволяет
любому типу объектов создать расширения пространства имен (предоставив процеду-
ру с названием Parse). Процедура Parse — это одна из процедур, которые могут быть
предоставлены для каждого типа объектов при создании типа (табл. 11.8).
Таблица 11.8. Процедуры объекта, предоставляемые при определении
нового типа объектов
Процедура
Когда вызывается
Примечания
Open
Для каждого нового описателя
Используется редко
Parse
Для типов объектов, которые расширя-
ют пространство имен
Используется для файлов и ключей
реестра
Close
При последнем закрывании описателя
Очистка видимых побочных эффектов
Delete
При последнем снятии косвенности
описателя
Объект будет в ближайшее время
удаляться
Security
Получить или установить дескриптор
безопасности объекта
Защита
OueryName
Получить имя объекта
Редко используется вне ядра
Процедура Open используется редко, поскольку поведение диспетчера объектов по
умолчанию — это именно то, что нужно, и поэтому эта процедура определена как NULL
почти для всех типов объектов.
Процедуры Close и Delete представляют собой другие фазы работы с объектом. Когда
закрывается последний описатель объекта, могут потребоваться действия по очистке
состояния (которые выполняются процедурой Close). Когда из объекта удаляется по-
следняя ссылка на указатель, вызывается процедура Delete, чтобы подготовить объект
к удалению и утилизировать его память. Для файловых объектов обе эти процедуры
реализованы как обратные вызовы в диспетчер ввода-вывода, как раз и являющийся
тем компонентом, который объявил тип объекта «файл». Операции диспетчера объек-
тов приводят к соответствующим операциям ввода-вывода, которые посылаются вниз
по связанному с файлом стеку устройств (основную работу делает файловая система).
Процедура Parse используется для открытия или создания объектов (вроде файлов
и ключей реестра), которые расширяют пространство имен NT. Когда диспетчер
объектов пытается открыть объект по имени и встречает листовой узел в той части
пространства имен, которой он управляет, он проверяет, указал ли тип для объекта
листового узла процедуру Parse. Если указал, то он вызывает эту процедуру, переда-
вая ей неиспользованную часть маршрута. Например, в файловых объектах листовой
узел — это объект устройства, представляющий конкретный том файловой системы.
Процедура Parse реализована диспетчером ввода-вывода, в результате она приводит
к операции ввода-вывода в файловую систему (для заполнения файлового объекта,
11.3. Структура системы
975
который будет ссылаться на открытый экземпляр файла на томе, к которому относится
маршрут). Мы изучим этот пример по шагам чуть позже.
Процедура QueryName используется для поиска имени, связанного с объектом. Проце-
дура Security используется для получения, настройки или удаления дескрипторов без-
опасности объекта. Для большинства объектных типов эта процедура предоставляется
как стандартная точка входа в компоненте «монитор безопасности» исполнительного
уровня.
Обратите внимание на то, что процедуры, указанные в табл. 11.8, самых полезных
операций с объектами, таких как чтение или запись файлов (или сброс и установка
семафоров), не выполняют. Вместо этого процедуры диспетчера объектов предостав-
ляют функции, необходимые для правильной настройки доступа к объектам и очистка
объектов после прекращения работы с ними. Объекты становятся полезными за счет
API-функций, работающих со структурами данных, которые содержатся в объектах.
Такие системные вызовы, как NtReadFile и NtWriteFile, используют таблицу описателей
процессов, созданную диспетчером объектов для преобразования описателя в ссы-
лочный указатель на исходный объект, например на файловый объект, содержащий
данные, необходимые для реализации системных вызовов. Кроме этих обратных вы-
зовов диспетчер объектов предоставляет также набор общих объектных процедур для
таких операций, как создание объектов и типов объектов, дублирование описателей,
получение указателя со ссылкой из описателя или имени, а также сложение и вычита-
ние количества ссылок на заголовок объекта и NtClose (обобщенная функция, которая
закрывает описатели всех типов).
Несмотря на то что пространство имен объектов чрезвычайно важно для работы
всей системы, очень мало кто знает о его существовании, поскольку оно не видимо
для пользователей без использования специальных инструментов просмотра. Один
из таких инструментов — это winobj, который можно получить бесплатно по адресу
www.microsoft.com/technet/sysinternals
. После запуска этот инструмент показывает
пространство имен объектов, которое обычно содержит перечисленные в табл. 11.9
каталоги объектов (а также некоторые другие).
Таблица 11.9. Некоторые стандартные каталоги пространства имен объектов
Каталог
Содержимое
\??
Начальное место для поиска устройств MS-DOS вроде С:
\DosDevices
Официальное название для \??, фактически символическая ссылка
на \??
\Device
Все обнаруженные устройства ввода-вывода
\Driver
Объекты, которые соответствуют всем загруженным драйверам
устройств
\ObjectTypes
Объекты типов (такие, как перечисленные в табл. 11.12) — описание
типов объектов
\Windows
Объекты для отправки сообщений всем окнам графического интерфей-
са пользователя Win32
\BaseNamedObjects
Создаваемые пользователем объекты Win32, такие как семафоры,
мьютексы и т. д.