Необходим для изменения
состояния объекта "порт"
|
Таблица 2.
У порта можно запрашивать количество необработанных
запросов с помощью функции NtQueryIoCompletion. Хотя в [3] утверждается, что
эта функция определяет, находится ли порт в сигнальном состоянии, на самом деле
она возвращает количество клиентских запросов в очереди. Это довольно важная
информация, которую почему-то опять решили от нас скрыть.
Давайте более детально рассмотрим, как создается и
функционирует порт завершения ввода/вывода [4].
При создании порта функцией CreateIoCompletionPort
вызывается внутренний сервис NtCreateIoCompletion. Объект "порт"
представлен следующей структурой [5]:
typedef stuct _IO_COMPLETION
{
KQUEUE Queue;
} IO_COMPLETION;
|
То есть, по существу, объект "порт
завершения" является объектом "очередь исполнительной системы"
(KQUEUE). Вот как представлена очередь:
typedef stuct _KQUEUE
{
DISPATCHER_HEADER Header;
LIST_ENTRY EnrtyListHead; //очередь пакетов
DWORD CurrentCount;
DWORD MaximumCount;
LIST_ENTRY
ThreadListHead; //очередь ожидающих потоков
} KQUEUE;
|
Итак, для порта выделяется память, и затем происходит
его инициализация с помощью функции KeInitializeQueue. (все, что касается
такого супернизкого устройства порта, взято из [4], остальное – из DDK и [3]).
Когда происходит связывание порта с объектом
"файл", Win32-функция CreateIoCompletionPort вызывает
NtSetInformationFile. Класс информации для этой функции устанавливается как
FileCompletionInformation, а в качестве параметра FileInformation передается
указатель на структуру IO_COMPLETION_CONTEXT [5] или
FILE_COMPLETION_INFORMATION [3].