
- •1.Объекты ядра
- •2. Учет пользователей объектов ядра
- •3. Защита объектов ядра
- •4. Таблица описателей объектов ядра
- •5. Создание объекта ядра
- •6. Закрытие объекта ядра
- •7. Совместное использование объектов ядра несколькими процессами
- •8. Наследование описателя объекта
- •9. Изменение флагов описателя
- •10. Именованные объекты
- •11. Дублирование описателей объектов
- •12. Синхронизация с потоков с помощью объектов ядра
- •13. Wait-функции
- •13.1. Побочные эффекты успешного ожидания
- •14. События
- •15. Семафоры
- •16. Мьютексы
- •17. Отказ от объекта-мьютекса
- •18. Мьютексы и критические секции
- •19. Сводная таблица объектов, используемых для синхронизации потоков
- •20. Порядок выполнения работы
- •21. Контрольные вопросы
4. Таблица описателей объектов ядра
При инициализации процесса система создает в нем таблицу описателей, используемую только для объектов ядра. Сведения о структуре этой таблицы и управлении ею незадокументированы.
Примерное содержание таблицы.
Таблица 4.1. Таблица описателей объектов ядра
Индекс |
Указатель на блок памяти объекта ядра |
Маска доступа (DWORD of Flag Bits) |
Флаги (DWORD of Flag Bits) |
1 |
0xF0000000 |
0x???????? |
0x00000000 |
2 |
0x00000000 |
(N/A) |
(N/A) |
3 |
0xF0000010 |
0x???????? |
0x00000001 |
5. Создание объекта ядра
Когда процесс инициализируется в первый раз, таблица описателей еще пуста. Но стоит одному из его потоков вызвать функцию, создающую объект ядра (например, CreateFileMapping), как ядро выделяет для этого объекта блок памяти и инициализирует его, далее ядро просматривает таблицу описателей, принадлежащую данному процессу, и отыскивает свободную запись. Поскольку таблица еще пуста, ядро обнаруживает структуру с индексом равным единице и инициализирует ее. Указатель устанавливается на внутренний адрес структуры данных объекта, маска доступа — на доступ без ограничений и, наконец, определяется последний компонент — флаги.
Все функции, создающие объекты ядра, возвращают описатели, которые привязаны к конкретному процессу и могут быть использованы в любом потоке данного процесса. Значение описателя представляет собой индекс в таблице описателей, принадлежащей процессу, и таким образом идентифицирует место, где хранится информация, связанная с объектом ядра. Вот поэтому при отладке своего приложения и просмотре фактического значения описателя объекта ядра можно видеть такие малые величины: 1, 2 и т. д. Но помните, что физическое содержимое описателей не задокументировано и может быть изменено. Кстати, в Windows 2000 это значение определяет, по сути, не индекс, а скорее байтовое смещение нужной записи от начала таблицы описателей.
Всякий раз, когда происходит вызов функцию, принимающую описатель объекта ядра как аргумент, ей передается значение, возвращенное одной из Create-функций. При этом функция смотрит в таблицу описателей, принадлежащую процессу, и считывает адрес нужного объекта ядра.
Если передан неверный индекс (описатель), функция завершается с ошибкой и GetLastError возвращает 6 (ERROR_INVALID_HANDLE). Это связано с тем, что на самом деле описатели представляют собой индексы в таблице, их значения привязаны к конкретному процессу и недействительны в других процессах.
Если вызов функции, создающей объект ядра, оказывается неудачен, то обычно возвращается 0 (NULL). Такая ситуация возможна только при острой нехватке памяти или при наличии проблем с защитой. К сожалению, отдельные функции возвращают в таких случаях не 0, а -1 (INVALID_HANDLE_VALUE). Например, если CreateFile не сможет открыть указанный файл, она вернет именно INVALID_HANDLE_VALUE. Надо быть осторожным при проверке значения, возвращаемого функцией, которая создает объект ядра. Так, для CreateMutex проверка на INVALID_HANDLE_VALUE бессмысленна.