3.1.1 Процедура DriverEntry

Здесь выполняются типичные для инициализации драйвера драйвера действия.

Регистрируются точки входа в драйвер:

pDriverObject->DriverUnload = SpectatorDriverUnload;

PDRIVER_DISPATCH * majorFunction = pDriverObject->MajorFunction;

majorFunction[ IRP_MJ_CREATE ] = SpectatorDispatchCreate;

majorFunction[ IRP_MJ_CLOSE ] = SpectatorDispatchClose;

majorFunction[ IRP_MJ_DEVICE_CONTROL ] = SpectatorDispatchDeviceControl;

Создаётся объект устройства с именем DEVICE_NAME:

#define DEVICE_NAME L"\\Device\\Spectator"

RtlInitUnicodeString( &deviceName, DEVICE_NAME );

status = IoCreateDevice

(pDriverObject,

sizeof( DEVICE_EXTENSION ),

&deviceName,

FILE_DEVICE_SPECTATOR,

FILE_DEVICE_SECURE_OPEN,

FALSE,

&pDeviceObject);

Для созданного обекта устройства регистрируется символьная ссылка SYMBOLIC_LINK:

#define SYMBOLIC_LINK L"\\DosDevices\\Spectator"

RtlInitUnicodeString( &symbolicLink, SYMBOLIC_LINK );

status = IoCreateSymbolicLink( &symbolicLink, &deviceName );

Создаётся объект ядра мьютекс:

NTSTATUS CreateMutex()

{BEGIN_FUNC( CreateMutex );

NTSTATUS status = STATUS_SUCCESS;

status = _ExAllocatePool( g_pMutex, NonPagedPool, sizeof( KMUTEX ) );

if ( NT_SUCCESS( status ) )

{KeInitializeMutex( g_pMutex, 0 );

status = STATUS_SUCCESS;}

END_FUNC( CreateMutex );

return ( status );}

Впервые загружается информация о процессах и их потоках:

if ( LockInfo() == STATUS_SUCCESS )

{ReloadInfo();

UnlockInfo();}

Функции LockInfo() и UnlockInfo() являются просто напросто функциями-обёртками для функций LockMutex() и UnlockMutex() соответственно. Первая из последних двух функций ожидает на объекте ядра мьютекс.

Объекты ядра «мьютексы» гарантируют потокам взаимоисключающий доступ к един ственному ресурсу. Отсюда и произошло название этих объектов (mutual exclusion, mutex). Они содержат счетчик числа пользователей, счетчик рекурсии и переменную, в которой запоминается идентификатор потока. Мьютексы ведут себя точно так же, как и критические секции. Однако, если последние являются объектами пользователь ского режима, то мьютексы — объектами ядра. Кроме того, единственный объект-мью текс позволяет синхронизировать доступ к ресурсу нескольких потоков из разных процессов; при этом можно задать максимальное время ожидания доступа к ресурсу.

Именно благодаря этому мьютексу обеспечивается требование по безопасности при обращении к хранимой информации.

Инициализируется работа таймера:

Таймер необходим для того, чтобы с определённым интервалом обновлять хранимую информацию.

Для этого создаётся объект ядра «таймер»:

status = _ExAllocatePool( g_pTimer, NonPagedPool, sizeof( KTIMER ) );

KeInitializeTimerEx( g_pTimer, SynchronizationTimer );

Замечание: память под объекты ядра должна выделяться исключительно в нестраничном пуле (ключевое слово NonPagedPool).

Таймеры могут быть двух типов:

SynchronizationTimer — по истечении указанного временного интервала или очередного периода, он переводится в сигнальное состояние, пока один из потоков, ждущих его, не будет пробуждён. Тогда же таймер переводится в несигнальное состояние.

NotificationTimer — по истечении указанного временного интервала или очередного периода, он переводится в сигнальное состояние, причём пробуждаются все потоки ожидающие на нём. Такой таймер остаётся в сигнальном состоянии до тех пор, пока он не будет явно переведён в несигнальное.

Для того, чтобы выполнять какую-то полезную работу по таймеру, необходимо зарегистрировать DPC-процедуру OnTimer(). Для неё необходимо создать собственный DPC-объект, который будет периодически ставится в общесистемную очередь:

status = _ExAllocatePool( g_pTimerDpc, NonPagedPool, sizeof( KDPC ) );

KeInitializeDpc( g_pTimerDpc, OnTime, NULL );

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

OBJECT_ATTRIBUTES objectAttributes;

InitializeObjectAttributes( &objectAttributes, NULL, OBJ_KERNEL_HANDLE,

NULL, NULL );

status = PsCreateSystemThread( &hThread, THREAD_ALL_ACCESS, &objectAttributes,

NULL, NULL, UpdateThreadFunc, NULL );

KeInitializeEvent( g_pUpdateEvent, SynchronizationEvent, FALSE );

Замечание: объекты ядра «события» по своему типу идентичны объектам ядра «таймер».

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

0.00075233 [Spectator] ^^^^^^^^ OnTime ^^^^^^^^

0.00116579 [Spectator] ======== LockInfo ========

0.00118814 [Spectator] ======== ReloadInfo ========

0.99727142 [Spectator] ^^^^^^^^ OnTime ^^^^^^^^

1.00966775 [Spectator] ======== LockInfo ========

1.00968981 [Spectator] ======== ReloadInfo ========

1.99729049 [Spectator] ^^^^^^^^ OnTime ^^^^^^^^

2.05610037 [Spectator] ======== LockInfo ========

2.05632067 [Spectator] ======== ReloadInfo ========

2.99727035 [Spectator] ^^^^^^^^ OnTime ^^^^^^^^

2.99741030 [Spectator] ======== LockInfo ========

2.99743295 [Spectator] ======== ReloadInfo ========

3.99727631 [Spectator] ^^^^^^^^ OnTime ^^^^^^^^

3.99739385 [Spectator] ======== LockInfo ========

3.99741673 [Spectator] ======== ReloadInfo ========

4.99728107 [Spectator] ^^^^^^^^ OnTime ^^^^^^^^

4.99742365 [Spectator] ======== LockInfo ========

4.99744749 [Spectator] ======== ReloadInfo ========

5.99728870 [Spectator] ^^^^^^^^ OnTime ^^^^^^^^

5.99742651 [Spectator] ======== LockInfo ========

5.99744844 [Spectator] ======== ReloadInfo ========

Здесь OnTime – момент входа в процедуру таймера OnTimer, LockInfo – момент, когда пробудился поток, отвечающий за обновление информации, ReloadInfo – момент, когда информация была действительно обновлена.

Как видно из перехвата, в первые две секунды периодичность не на высоком уровне, но потом ситуация стабилизируется и точность улучшается, как и было заявлено, до одной миллисекунды.

После всех этих действий, наконец, запускается таймер:

LARGE_INTEGER dueTime = RtlConvertLongToLargeInteger( 0 );

BOOLEAN existed = KeSetTimerEx( g_pTimer, dueTime, g_timerPeriod, g_pTimerDpc );

Здесь dueTime – время до первого вызова процедуры OnTime(), а g_timerPeriod – период дальнейших вызовов.

Вконце концов, в процедуре DriverEntry происохдит обнуление счётчика пользовательских приложений-клиентов, получивших описатель данного драйвера: pDeviceExtension->clientCount = 0;

Благодаря одной этой переменной становится возможным одновременное обращение к драйверу сразу нескольких пользовательских приложений. Единственным ограничением для них ялвяется эксклюзивность доступа к информации о процессах и их потоках.

 

3.1.2 DriverUnload

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

 


Информация о работе «Профилировщик приложений»
Раздел: Информатика, программирование
Количество знаков с пробелами: 37785
Количество таблиц: 1
Количество изображений: 5

Похожие работы

Скачать
18932
0
11

... 100;i++)recursive(); //Вызываем 100 раз рекурсивную функцию 100х100 return 0; } Приложение простое по сути, но очень содержательное, так как эффективно демонстрирует основные возможности Quantify. В самом начале статьи мы выдвигали требование, по которому разработчикам не рекомендуется пользоваться рекурсивными функциями. Тестеры или разработчики, увидев диаграмму вызовов, выделят функцию, ...

Скачать
59903
1
4

... из которых ранее относились только к интеллектуальным возможностям человека. 2.  Инструментальное программное обеспечение 2.1 Сущность и понятие инструментального программного обеспечения Инструментальное программное обеспечение (ИПО) — программное обеспечение, предназначенное для использования в ходе проектирования, разработки и сопровождения программ. Применяется инструментальное ...

Скачать
249178
21
46

... системам линейных алгебраических уравнений с более чем одной неизвестной; MATLAB решает такие уравнения без вычисле-ния обратной матрицы. Хотя это и не является стандартным математическим обозначением, система MATLAB использует терминологию, связанную с обычным делением в одномерном случае, для описания общего случая решения совместной системы нескольких линейных уравнений. Два символа деления / ...

Скачать
73505
5
17

... . Время задержки сигнала при этом увеличивается до 9нс. Наиболее перспективным семейством КМОП микросхем считается семейство SN74AUC с временем задержки сигнала 1,9нс и диапазоном питания 0,8..2,7В. 3. ИНФОРМАЦИОННО-СПРАВОЧНАЯ СИСТЕМА   3.1 Определение и классификация БД   База данных – это информационная модель предметной области, совокупность взаимосвязанных, хранящихся вместе данных при ...

0 комментариев


Наверх