Иллюстрированный самоучитель по программированию систем защиты

Сериализация

События

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

При этом события могут быть двух видов:

  • События, при переводе которых в сигнальное состояние будет разблокирован только один поток, после чего событие автоматически переходит в не сигнальное состояние. Такие события носят название события синхронизации (synchronization events).
  • События, при переводе которых в сигнальное состояние будут разблокированы все ожидающие их потоки. Событие должно быть переведено в несигнальное состояние вручную. Такие события носят название оповещающих (notification event).

Функции работы с событиями:

  1. KelnitializeEvent() инициализирует событие. Память под событие уже должна быть выделена. При инициализации указывается тип – синхронизация или оповещение, а также начальное состояние – сигнальное или несигнальное. Имя события задать нельзя. Функция может быть использована в случайном контексте памяти на уровне IRQL PASSIVE_LEVEL.
  2. IoCreateNotificationEvent(), IoCreateSynchronizationEvent() создают новое или открывает существующее событие с заданным именем. Если объект с таким именем существует, он открывается, если не существует, то создается. Имя события обычно указывается в директории диспетчера объектов \BaseNamedObjects. Именно в этой директории содержатся имена событий, создаваемых или открываемых \Win32-функциями CreateEvent()/OpenEvent().
    Функция возвращает как указатель на объект-событие, так и его описатель в таблице описателя текущего процесса. Для уничтожения объекта необходимо использовать функцию ZwClose() с описателем в качестве параметра. Описатель должен быть использован в контексте того процесса, в котором он был получен на уровне IRQL PASSIVE_LEVEL.
  3. KeClearEvent() и KeResetEvent() сбрасывают указанное событие в несигнальное состояние. Отличие между функциями в том, что KeResetEvent() возвращает состояние события до сброса. Функции могут быть вызваны на уровне IRQL меньшем или равном DISPATCHJLEVEL.
  4. KeSetEvent() переводит событие в сигнальное состояние и получает предыдущее состояние. Одним из параметров является логическая переменная, указывающая, будет ли за вызовом KeSetEvent() немедленно следовать вызов функции ожидания. Если параметр TRUE, то гарантируется, что вызов этих двух функций будет выполнен как одна операция.

В случае событий оповещения сброс события в несигнальное состояние должен быть сделан вручную. Обычно это делает тот же код, который перевел событие в сигнальное состояние.

Следующий код корректно уведомляет все блокированные потоки о наступлении ожидаемого ими события:

KeSetEvent(&DeviceExt › Event, О, NULL);
KeClearEvent(&DeviceExt › Event);

Быстрые мьютексы

Быстрый мьютекс являются урезанным вариантом мьютекса, который не может быть рекурсивно захвачен. Поскольку быстрый мьютекс не является диспетчерским объектом, он не может использоваться функцией KeWaitForSingleObject() или KeWaitForMultipleObjects(). Вместо этого нужно использовать функцию ExAcquireFast Mutex(). Эквивалента быстрым мьютексам на пользовательском уровне нет, поэтому они могут использоваться только для синхронизации кода режима ядра.

Функции работы с быстрыми мьютексами:

  1. VOID ExInitializeFastMutex(IN PFAST_MUTEX FastMutex);
  2. VOID ExAcquireFastMutex(IN PFAST_MUTEX FastMutex);
  3. BOOLEAN ExTryToAcquireFastMutex(IN PFAST_MUTEX FastMutex);
  4. VOID ExReleaseFastMutex(IN PFAST_MUTEX FastMutex);
  5. VOID ExAcquireFastMutexUnsafe(IN PFAST_MUTEX FastMutex);
  6. VOID ExReleaseFastMutexUnsafe (IN PFAST_MUTEX FastMutex).
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.