Реферат по предмету "Информатика, программирование"


Профилировщик приложений

РАСЧЕТНО-ПОЯСНИТЕЛЬНАЯЗАПИСКА
к курсовомупроекту на тему:
Профилировщикприложений

Содержание
1. Введение
2. Аналитическийраздел
2.1. Техническоезадание
2.2. Обзорархитектуры Windows NT 5.x
2.3.Классификация драйверов
2.4. Общаяструктура Legacy-драйвера
2.4.1. ПроцедураDriverEntry
2.4.2. ПроцедураDriverUnload
2.4.3. Рабочиепроцедуры обработки IRP-пакетов
2.4.3.1.Заголовок IRP пакета
2.4.3.2. СтекIRP-пакета
2.4.3.3. Функцияобработки пакетов IRP_MJ_CREATE
2.4.3.4. Функцияобработки пакетов IRP_MJ_CLOSE
2.4.3.5. Функцияобработки пакетов IRP_MJ_DEVICE_CONTROL
2.4.4. ISR –процедура обработки прерываний
2.4.5. DPC –процедура отложенного вызова
3.Конструкторский раздел
3.1.Legacy-драйвер
3.1.1.Процедура DriverEntry
3.1.2.DriverUnload
3.1.3.DispatchCreate и DispatchClose
3.1.4.DispatchDeviceControl
3.1.4.1.IOCTL_LAST_CLIENT
3.1.4.2.IOCTL_LOCK_INFO и IOCTL_UNLOCK_INFO
3.1.4.3.IOCTL_PROCESS_FIRST и IOCTL_PROCESS_NEXT
3.1.4.4.IOCTL_THREAD_FIRST и IOCTL_THREAD_NEXT
3.1.4.5.IOCTL_OPEN_THREAD
3.1.4.6.IOCTL_CLOSE_THREAD
3.1.4.7.IOCTL_GET_THREAD_CONTEXT
3.2.Пользовательское приложение
4. Техническийраздел
4.1. Выбороперационной системы и среды программирования.
4.2. Интерфейс
4.3. Системныетребования
5. Заключение.
6. Списокиспользованной литературы.
 

1. Введение
Оченьчасто при разработке программного обеспечения возникает необходимость,проследить за его работой: сколько времени его потоки выполняются в режимеядра, сколько – в пользовательском режиме, сколько времени они проводят вожидании, а также количество переключений контекста из одного режима в другой.Всё это важно, так как каждый из режимов имеет свои особенности. В режиме ядракод выполняется быстрее, но существует потенциальная возможность поврежденияданных/кода системы. В противоположность режиму ядра, пользовательский режимограничен в предоставляемых ему сервисах так, чтобы его код не мог привести к крахусистемы. Для этой же цели в пользовательском режиме выполняются дополнительныепроверки, позволяющие предотваратить выполнение вредоносных инструкций. Поэтомускорость выполнения кода пользовательского режима существенно ниже. Количествопереключений контекста тоже влияет на скорость выполнения кода, так как этооперация является довольно дорогостоящей (около 2000 тактов). Это было хорошозаметно при разработке лабораторных работ и  курсового проекта по машиннойграфике: при рисовании изображения попиксельно с помощью функции SetPixel,скорость прорисовки была несоизмеримо меньше, чем при использовании буферапользовательского режима, в который постепенно заносилась информация о цветесоответствующих элементам буффера пикселям. Это происходило засчёт того, чтопри использовании функции SetPixel происходило два переключения контекста (изпользовательского режима в режим ядра и обратно) на один пиксель, а прииспользовании буфера, хранящего контекстно независимое представление цвета, — те же два переключения, но один раз на прорисовку целого кадра.
Такимобразом, возможность узнать вышеуказанную статистическую информацию о целевомпрограммном обеспечении, позволит своевременно заметить так называемые «узкие»места в программе, которые мешают улучшению производительности приложения вцелом.

2.Аналитический раздел
 
2.1Техническое задание
Цельюпредставленного курсового проекта является разработка простого профилировщикаприложений, который в себя включает:
Legacy-драйвер,который должен:
Периодическиобновлять информацию о процессах и их потоках;
Предоставлятьбазовую информацию о процессах и их потоках;
Предоставлятьаппаратный контекст выбранного потока;
Обеспечиватьбезопасное обращение к этой информации от нескольких пользовательских приложений-клиентов.
Пользовательскоеприложение, позволяющее:
Корректноустанавливать и удалять драйвер без необходимости перезагрузки системы;
Обращатьсяк драйверу с запросами для получении различной информации.
 
2.2Обзор архитектуры Windows NT 5.x
 
ВWindows приложения отделены от самой операционной системы. Код её ядравыполняется в  привилегированном режиме процессора (режим ядра), которыйобеспечивает доступ к системным данным и оборудованию. Код приложенийвыполняется в непривилегированном режиме процессора (пользовательский режим)с неполным набором интерфейсов, ограниченным доступом к системным данным и безпрямого доступа к оборудованию. Когда программа пользовательского режима вызываетсистемный сервис, процессор перехватывает вызов и переключает вызывающий потокв режим ядра. По окончании системного сервиса операционная система переключаетконтекст потока обратно в пользовательский режим и продолжает его выполнение.
Далеесхематично показана та часть архитектуры Windows, которая затронута даннымкурсовым проектом. Здесь не указываются такие компоненты, как: процессыподдержки системы, процессы сервисов, подсистемы окружения, уровеньабстрагирования от оборудования и поддержка окон и графики.
Пользовательскиеприложения — один из типов пользовательских процессов, выполняющихся впользовательском режиме, в рамках которого они ограничены использованиемнепривилегированных инструкций.
DLLподсистем — в Windows пользовательские приложения не могут вызывать сервисыоперационной системы напрямую, вместо этого они работают с одной илинесколькими DLL подсистем, назначение которых заключается в трансляциидокументированных функций в соответствующие внутренние (и обычнонедокументированные) вызовы системных сервисов.
Исполнительнаясистема — содержит базовые сервисы операционной системы, которые обеспечиваютуправление памятью, процессами и потоками, защиту, ввод-вывод и взаимодействиемежду процессами.
Ядро— содержит низкоуровневые функции операционной системы, которые поддерживают,например, планирование потоков, диспетчеризацию прерываний и исключений. Онотакже предоставляет набор процедур и базовых объектов, применяемыхисполнительной системой для реализации структур более высокого уровня.
Драйверы— служат для расширения функциональных возможностей ядра.

/>
 
2.3Классификация драйверов
Вотличие от пользовательского приложения, драйвер не является процессом и неимеет потока исполнения. Вместо этого управление драйверу передаётся врезультате запроса на ввод/вывод от пользовательского приложения или драйвера,либо возникает в результате прерывания. В первом случае контекст исполнениядрайвера точно известен — это прикладная программа. Во втором случае контекстисполнения может быть как известным, так и случайным — это зависит от контекстаисполнения функции вызывающего драйвера. В третьем случае контекст исполненияслучайный, поскольку прерывание (и, соответственно, исполнение кода драйвера)может произойти при выполнении любой прикладной программы.
Порасположению в стеке драйверов:
Драйверывысшего уровня — получают запросы от пользовательского приложения ивзаимодействуют с нижестоящими драйверами;
Промежуточныедрайверы — получают запросы от вышестоящих драйверов и взаимодействуют снижестоящими драйверами;
Драйверынизшего уровня — получают запросы от вышестоящих драйверов, осуществляютконечную обработку пакетов запросов.
Такжевыделяют понятие монолитного драйвера – драйвера высшего уровня, невзаимодействующего ни с какими другими драйверами.
Всвязи с усовершенствованием модели драйверов Windows (WDM – Windows DriverModel), в которой были добавлены поддержка Plug and Play и энергосберегающиетехнологии, драйвера стали разделять на:
Унаследованныедрайвера (Legacy-драйвера, драйвера «в стиле NT») — драйвера, написанные встаром манере, без поддержки нововведений;
WDM-драйвера– драйвера, которые удовлетворяют всем требованиям расширенной модели WDM.
 
2.4Общая структура Legacy-драйвера
Legacy-драйверимеет следующие основные точки входа:
DriverEntry– процедура загрузки драйвера;
DriverUnload– процедура выгрузки драйвера;
Рабочиепроцедуры обработки IRP-пакетов;
ISR-процедура(Interrupt Service Routine) – процедура обработки прерывания;
DPC-процедура(Deferred Procedure Call) – процедура отложенного вызова.
 
2.4.1Процедура DriverEntry
Даннаяпроцедура присутствует в любом драйвере и вызывается диспетчером ввода/вывода призагрузке драйвера.
Legacy-драйверывыполняют в ней существенно большую работу, нежели WDM-драйвера, так как онивынуждены выполнять работу процедуры AddDevice, обязательной для WDM-драйверов.Помимо решения инициализационных задач и регистрации точек входа рабочихпроцедур обработки поддерживаемых IRP-пакетов и процедуры выгрузки драйвера,здесь:
Определяетсяаппаратное обеспечение, которое драйвер будет контролировать;
Создаютсяобъекты устройств (функция IoCreateDevice) для каждого физического илилогического устройства под управлением данного драйвера;
Дляустройств, которые должны быть видимы пользовательским приложениям, создаютсясимвольные ссылки (функция IoCreateSymbolicLink);
Принеобходимости, устройство подключается к объекту прерываний. В случае, еслиISR-процедура требует использования DPC-процедуры, то соответсвующий ей объектсоздаётся и инициализируется на этом этапе;
Выделениепамяти, необходимой для работы драйвера.
 
2.4.2Процедура DriverUnload
Диспетчерввода/вывода вызывает данну процедуру при динамической выгрузке драйвера. Этапроцедура выполняет действия, «обратные» тем, что выполняются в процедуреDriverEntry.
ДляLegacy-драйверов характерны следующие шаги:
Длянекоторых типов аппаратуры необходимо сохранить ее состояние в системномреестре, т.к.  при последующей загрузке драйвера эти данные могут бытьиспользованы;
Еслипрерывания разрешены для обслуживаемого устройства, то процедура выгружкидолжна запретить их и произвести отключение от объекта прерываний. Ситуация,когда устройство будет порождать прерывания для несуществующего объектапрерывания, неминуемо приведет к краху системы;
Удалениесимвольной ссылки из пространства имен, видимого пользовательскими приложениями(IoDeleteSymbolicLink);
Удалениеобъекта устройства (IoDeleteDevice);
Освобждениепамяти, выделенной драйверу в процессе работы.
 
2.4.3Рабочие процедуры обработки IRP-пакетов
Всефункции, зарегистрированные в процедуре DriverEntry путём заполнения массиваMajorFunction, вызываются Диспетчером ввода/вывода для обработки соответсвующихзапросов от клиентов драйвера. Эти запросы всегда оформлены в виде специальныхструктур данных – IRP-пакетов, память под которые выделяется Диспетчеромввода/вывода в нестраничном системном пуле. Структура IRP-пакета такова, что онсостоит из заголовка фиксированного размера и IRP-стека, размер которогозависит от количества объектов устройств в стеке.
2.4.3.1 Заголовок IRP пакета.Структура заголовка IRP-пакета имеет следующие поля:
ПолеIoStatus типа IO_STATUS_BLOCK содержит два подполя:
Statusсодержит значение, которое устанавливает драйвер после обработки пакета;
ВInformation чаще всего помещается число переданных или полученных байт.
ПолеAssociatedIrp.SystemBuffer типа PVOID содержит указатель на системный буфер дляслучая, если устройство поддерживает буферизованный ввод/вывод;
ПолеMdlAddress типа PMDL содержит указатель на MDL-список, если устройство поддерживаетпрямой ввод вывод;
ПолеUserBuffer типа PVOID содержит адрес пользовательского буфера для ввода/вывода;
ПолеCancel типа BOOLEAN — это индикатор того, что пакет IRP должен бытьаннулирован.
/>
 

2.4.3.2Стек IRP-пакета. Основное назначение ячеек стека IRP-пакетасостоит в том, чтобы хранить функциональный код и параметры запроса наввод/вывод. Для запроса, который адресован драйверу самого нижнего уровня,соответствующий IRP пакет имеет только одну ячейку стека. Для запроса, которыйпослан драйверу верхнего уровня, Диспетчер ввода/вывода создает пакет IRP снесколькими стековыми ячейками – по одной для каждого объекта устройства.
Каждаяячейка IRP-стека содержит:
MajorFunctionтипа UCHAR – это код, описывающий назначение операции;
MinorFunctionтипа UCHAR – это код, описывающий суб-код  операции;
DeviceObjectтипа PDEVICE_OBJECT – это указатель на объект устройства, которому быладресован данный запрос IRP;
FileObjectтипа PFILE_OBJECT – файловый объект для данного запроса;
Parametersтипа union – применение зависит от значения MajorFunction.
Диспетчерввода/вывода использует поле MajorFunction для того, чтобы извлечь из массиваMajorFunction нужную для обработки запроса процедуру.
/>

Каждаяпроцедура обработки IRP пакетов должна в качестве параметров принимать:
Указательна объект устройства, для которого предназначен IRP запрос;
Указательна пакет IRP, описывающий этот запрос;
/>2.4.3.3 Функцияобработки пакетов IRP_MJ_CREATE. Данная функцияпредназначена для обработки запросов на получение дескриптора драйвера отпользовательских приложений или вышестоящих драйверов. Как правило, эта функцияпросто помечает IRP-пакет, как завершённый.
2.4.3.4 Функция обработки пакетов IRP_MJ_CLOSE.Данная функция предназначена для обработки запросов на закрытие дескрипторадрайвера от пользовательских приложений или вышестоящих драйверов. Как правило,эта функция просто помечает IRP-пакет, как завершённый.
2.4.3.5 Функция обработки пакетовIRP_MJ_DEVICE_CONTROL. Данная функция позволяет обрабатыватьрасширенные запросы от клиентов пользовательского режима, служат чаще всего дляобмена данными  между приложением и драйвером. Такой запрос может бытьсформирован посредством вызова функции DeviceIoControl из пользовательскогорежима.
Здесьиспользуются IOCTL-коды (I/O Control code), часть из которых предопределенаоперационной системой, а часть может создаваться разработчиком драйвера. Такойкод задаётся в запросе Диспетчером ввода/вывода при формировании IRP-пакета.
Операциидрайвера, которые работают с IOCTL-запросами, часто требуют задания буфернойобласти для размещения входных или выходных данных. Возможна такая ситуация,когда в одном запросе используются оба буффера.
Методдоступа к данным, обеспечиваемый Диспетчером ввода/вывода, определяется вIOCTL-коде. Такими методами могут быть:
METHOD_BUFFERED:входной пользовательский буфер копируется в системный, а по окончании обработкисистемный копируется в выходной пользовательский буфер.
METHOD_IN_DIRECT:необходимые страницы пользовательского буфера загружаются с диска в оперативнуюпамять и блокируются. Далее с помощью DMA осуществляется передача данных междуустройством и пользователем.
METHOD_OUT_DIRECT:необходимые страницы пользовательского буфера загружаются с диска в оперативнуюпамять и блокируются. Далее с помощью DMA осуществляется передача данных междуустройством и пользователем.
METHOD_NEITHER:при данном методе передачи не производится проверка доступности памяти, невыделяются промежуточные буфера и не создаются MDL. В IRP-пакете передаютсявиртуальные адреса буферов в адресном пространстве инициатора запросаввода/вывода.
Вданном случае флаги, определяющие тип буферизации в объекте устройства, неимеют значения при работе с IOCTL запросами. Механизм буферизованного обменаопределяется при каждом задании значения IOCTL в специально предназначенном дляэтого фрагменте этой структуры данных. Данный подход обеспечивает максимальнуюгибкость при работе с вызовом пользовательского режима DeviceIoControl.
Сточки зрения драйвера, доступ к буферным областям, содержащим данные илипредназначенным для данных, осуществляется с помощью следующих полей структур[1]: METHOD_BUFFERED METHOD_IN_DIRECT или METHOD_OUT_DIRECT METHOD_NEITHER
Input
Буфер с данными
Использует буферизацию (системный буфер)
Адрес буфера в системном адресном пространстве указан в pIrp->AssociatedIrp.SystemBuffer Клиентский виртуальный адрес в Parameters. DeviceIoControl. Type3InputBuffer Длина указана в Parameters.DeviceIoControl.InputBufferLength
Output
Буфер для данных
Использует буферизацию (системный буфер)
Адрес буфера в системном адресном пространстве указан в pIrp-> AssociatedIrp. SystemBuffer Использует прямой доступ, клиентский буфер преобразован в MDL список, указатель на который размещен в pIrp->MdlAddress Клиентский виртуальный адрес в pIrp->UserBuffer Длина указана в Parameters.DeviceIoControl.OutputBufferLength
/>2.4.4 ISR– процедура обработки прерываний
Этуфункцию драйвер регистрирует, чтобы она получала управление в момент, когдааппаратура, обслуживаемая драйвером, передала сигнал прерывания. Задача этойфункции выполнить минимальную работу и зарегистрировать процедуру отложенноговызова (DPC) для обслуживания прерывания. Вызов диспетчером прерываний ядра можетпроизойти в любом контексте: как ядра, так и пользовательского процесса.
 
2.4.5DPC – процедура отложенного вызова
Такиепроцедуры выполняются при более низком уровне запроса прерывания (IRQL), чемISR, что позволяет не блокировать другие прерывания. В них может выполняться всяили завершаться начатая в ISR работа по обслуживанию прерываний.

3.Конструкторский раздел
Таквыглядит схема взаимодействия пользовательского приложения с драйвером черезкомпоненты системы:
/>
 
3.1Legacy-драйвер
ВLegacy-драйвере данного курсового проекта реализованы следующие процедуры:
DriverEntry;
DriverUnload;
DispatchCreate(обработка IRP_MJ_CREATE-пакета);
DispatchClose(обработка IRP_MJ_CLOSE-пакета);
DispatchDeviceControl(обработка IRP_MJ_DEVICE_CONTROL-пакета).
 
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:
#defineDEVICE_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:
#defineSYMBOLIC_LINK    L"\\DosDevices\\Spectator"
RtlInitUnicodeString(&symbolicLink, SYMBOLIC_LINK );
status= IoCreateSymbolicLink( &symbolicLink, &deviceName );
Создаётсяобъект ядра мьютекс:
NTSTATUSCreateMutex()
{BEGIN_FUNC(CreateMutex );
NTSTATUSstatus = 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_ATTRIBUTESobjectAttributes;
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_INTEGERdueTime = RtlConvertLongToLargeInteger( 0 );
BOOLEANexisted = KeSetTimerEx( g_pTimer, dueTime, g_timerPeriod, g_pTimerDpc );
ЗдесьdueTime – время до первого вызова процедуры OnTime(), а g_timerPeriod – периоддальнейших вызовов.
Вконцеконцов, в процедуре DriverEntry происохдит обнуление счётчика пользовательскихприложений-клиентов, получивших описатель данного драйвера: pDeviceExtension->clientCount= 0;
Благодаряодной этой переменной становится возможным одновременное обращение к драйверусразу нескольких пользовательских приложений. Единственным ограничением для нихялвяется эксклюзивность доступа к информации о процессах и их потоках.
 
3.1.2DriverUnload
Вэтой процедуре, если число клиентов драйвера равно нулю, происходит удалениевсех объектов созданных для организации работы таймера, удаление мьтекса,объекта устройства и его символьной ссылки. Если же число клиентов отлично отнуля, то драйвер не выгружается, так как, в противном случае, это нарушитнормальную работу других пользовательских приложений-клиентов.
 
3.1.3DispatchCreate и DispatchClose
Вэтих функциях происходит учёт количества открытых описателей данного драйвераполученных с помощью API-вызова CreateFile(). Сколько описателей было открыто –столько же должно быть закрыто API-вызовом CloseHandle(). Иначе драйвер поокончании работы пользовательского приложения останется в операционной системе,что, естественно, крайне не желательно.
 
3.1.4DispatchDeviceControl
Этапроцедура обслуживает IOCTL-запросы от пользовательских приложений посылаемыеAPI-вызовом DeviceIoControl(). В данном курсовом проекте взаимодействие сдрайвером большею частью и построено на их применении, здесь реализованаосновная функциональность драйвера: то, для чего он и предназначался. Поэтомуданная процедура наиболее объёмна.
Сначала,назависимо от конкретного IOCTL-запроса, получается указатель на ячейкуIRP-стека IRP-пакета, предназначенную для объекта устройства драйвера:
PIO_STACK_LOCATIONpIrpStack = IoGetCurrentIrpStackLocation( pIrp );
Далее,из этой ячейки извлекается код IOCTL-запроса, на основе которого с помощьюоператора switch происходит дополнительная диспетчеризация IRP-пакета.
Врассматриваемом драйвере все IOCTL-запросы используют буферизованный методпередачи данных, так как во всех запросах их объём действительно невелик. Притаком подходе передачи данных в системном нестраничном пуле выделяется столькопамяти, чтобы поместился больший из входного и выходного буферов. Перед началомобработки запроса содержимое входного пользовательского буфера копируется всистемный буфер, а по завершении из системного – в выходной пользовательскийбуфер. Так как для обоих пользовательских буферов используется всего лишь одинсистемный, то необходимо быть аккуратным при обработке данных, так как естьвероятность при записи повредить ещё непрочитанные входные данные и тогда онибудут утеряны навсегда.
Длины(в байтах) пользовательских буферов, входного и выходного, извлекаются из поляParameters ячейки IRP-стека: Parameters.DeviceIoControl.InputBufferLengthи Parameters.DeviceIoControl.OutputBufferLength соответственно.А адрес системного буфера извлекается из заголовка IRP-пакета: AssociatedIrp.SystemBuffer.
3.1.4.1 IOCTL_LAST_CLIENT.Входные данные: [нет]
Выходныеданные:      [нет]
ДанныйIOCTL-запрос служит для обращения к драйверу, чтоб тот дал ответ на вопросявляется ли инициатор запроса единственным клиентом, работающим с драйвером наданный момент. Этот запрос посылается драйверу каждым пользовательски приложением,когда оно собирается вот-вот завершиться. Если ответ положительный, то этоприложение пытается завершить работу драйвера, иначе оно просто завершается,будучи уверенным, что есть другие клиенты, работающие с драйвером и что топриложение, которое будет завершаться последним, позаботится о выгрузкедрайвера.
3.1.4.2 IOCTL_LOCK_INFO иIOCTL_UNLOCK_INFO. Входные данные:[нет]
Выходныеданные: [нет]
ПервыйIOCTL-запрос из этой служит для захвата пользовательским приложением системнойинформации в монопольное пользование. Другой – соответствено, для осовбожденияэтого ресурса. В них просто вызываются одноимённые функции LockInfo() иUnlockInfo(), о которых было рассказано ранее, когда речь шла о процедуреDriverEntry данного раздела.
3.1.4.4 IOCTL_PROCESS_FIRST иIOCTL_PROCESS_NEXT. Входные данные:[нет]
Выходныеданные: структура с базовой информацие о процессе.
Этапара IOCTL-запросов позволяет их инициатору последовательно проссматриватьструктуры, описывающие запущенные процессы в системе. Каждый из них вызываетодноимённую функцию ProcessFirst() и ProcessNext() соответственно. Перваяфункция устанавливает указатель на первую запись, а вторая перемещает указательна следующую, если такая имеется. Результатом выполнения каждой из этих функцийявляется заполненная структура с информацией оп процессе, если не достигнутконец списка. В том случае, когда конец списка всё-таки достигается, IRP-пакет,тем не менее, помечается как успешно обработанный, но значение количествапереданных байтов устанавливается равным нулю, что и позволяетпользовательскому приложению правильно распознать такую ситуацию и своевременнопрекратить посылать драйверу дальнейшие IOCTL_PROCESS_NEXT-запросы.
3.1.4.5 IOCTL_THREAD_FIRST иIOCTL_THREAD_NEXT. Входные данные:[нет]
Выходныеданные: структура с базовой информацие о потоке.
Каки в предыдущем пункте, эта пара IOCTL-запросов позволяет их инициаторупоследовательно проссматривать структуры, описывающие потоки выбранногопроцесса. Логика обработки этих запросов аналогична получению информации опроцессах.
3.1.4.6 IOCTL_OPEN_THREAD.Входные данные: права доступа, уникальный идентификатор целевого потока.
Выходныеданные: описатель целевого потока.
Приобработке данного IOCTL-запроса осуществляется попытка открыть описательпотока, имеющего указанный идентификатор с правами, которые были запрошеныпользовательским приложением-клиентом.
3.1.4.6 IOCTL_CLOSE_THREAD.Входные данные: описатель целевого потока.
Выходныеданные: [нет].
Вовремя обработки этого IOCTL-запроса предпринимается попытка закрыть описательпотока, открытый ранее с помощью IOCTL_OPEN_THREAD-запроса.
3.1.4.7 IOCTL_GET_THREAD_CONTEXT.Входные данные: структура аппаратного контекста, описатель целевогопотока.
Выходныеданные: структура аппаратного контекста.
ЭтотIOCTL-запрос наиболее полно использует возможности API-вызова DeviceIoControl,так как здесь задействованы оба, входной и выходной, буферы. На вход поступаетструктура для аппаратного контекста с инициализированным полемыCONTEXT::ContextFlags, указывающим какие группы регистров аппаратного контекстадолжны быть возвращены в этой структуре при удачном завершении запроса. В этомпроекте запрашивается весь аппаратный контекст.
 
3.2Пользовательское приложение
Пользовательскоеприложение включает в себя два класса: CDialog и CDriver. Как понятно изназваний эти классы отвечают соответственно за взаимодействие с пользователемчерез диалоговое окно приложения и взаимодействие с драйвером преимущественночерез IOCTL-запросы.
Призапуске экземпляр пользовательского приложения первым делом пытается установитьдрайвер, в том случае, если это не было сделано ранее другим экземпляром. Еслиустановка вызвала ошибку, то пользователю выдаётся соответствующее сообщение, вкотором в текстовом виде указывается причина её возникновения, если она былапредусмотрена, иначе – просто указывается её код. Пользователь может запроситьустановку драйвера ещё раз, дав положительный ответ на соответствующеепредложение программы. Такая процедура повторятся до тех пор, пока установкадрайвера не пройдёт успешно либо пользователь откажется от повторной попытки.
Послеэтого загружается ниспадающий список запущенных процессов, отсортированных валфавитном порядке по своим именам, выбирается первый процесс из списка, и ужеего потоки отображаются во втором ниспадающем списке. Эти списки обновляютсякаждый раз, когда пользователь хочет выбрать другой процесс или поток, так какдля этого ему нужны последние сведения.
Далеесоздаётся таймер, работа которого никак не связана с работой таймера драйвера.Этот таймер отвечает за периодичный вывод полученной от драйвера информации наформу диалога.
Этаинформация получается через драйвера, как уже говорилось, с помощью API-вызоваDeviceIoControl:
BOOLDeviceIoControl
(HANDLE,
DWORD,
LPVOID, DWORD ,
LPVOID, DWORD ,
LPDWORD,
LPOVERLAPPED);
HANDLE – описательустройства, которому посылается запрос;
DWORD – кодIOCTL-запроса;
LPVOID – адресвходного буфера;
DWORD – длинавходного буфера;
LPVOID – адресвыходного буфера;
DWORD - длинавыходного буфера;
LPDWORD – количествопереданных байтов;
LPOVERLAPPED – структура,необходимая при использовании асинхронного выполнения запроса, чего нет вданном приложении.
Использованиеэтого API-вызова полностью инкапсулировано в классе CDriver, в котором длявыполнения каждого запроса реализован отдельный метод с именем, близким кназванию IOCTL-запроса, что обеспечивает интуитивное понимание интерфейса этогокласса.
Такжеэтот класс инкапсулирует в себя использование Менеджера управления сервисами(SCM — Service Control Manager), с помощью которого осуществляется динамическаяустановка, запуск, останов и удаление драйвера.

4.Технический раздел
 
4.1Выбор операционной системы и среды программирования
Вкачестве операционной системы была выбрана система Widows. Это обусловлено тем,что операционная система DOS уже устарела в силу многих причин (мы уже ушли отОС, работающих в однозадачном режиме),  а других операционных систем дляперсональных машин с хорошим интерфейсом, действительно удобных дляпользователя, еще нет. Windows по прежнему остается самой распространенной ОСдля ПК. Кроме того различные среды разработки программных продуктов разработаныименно под Windows:
VisualC++, Visual Basic, Borland C++ Builder, Delphi и другие.
Языкомнаписания пользовательской программы был выбран С++. Язык С++ дает оченьбогатые возможности для программистов и, пожалуй является наиболеераспространенным в их среде. Это очень мощный операторный язык. Кроме того, онобеспечивает достаточную свободу в написании программ, в то время как Pascalставит очень узкие рамки, в частности, в описании переменных и не даетвозможности построения сложных операторных выражений. Языком написания драйверабыл выбран С. Применение этого языка обеспечивает переносимость меджусистемами: максимум, что придётся сделать – это пересобрать драйвер. В качествесреды разработки была выбрана Microsoft Visual Studio .Net, поскольку она даетмощные и удобные средства не только визуальной разработки интерфейсапрограммного продукта, но и настройки проектов, что позволяет эффективноорганизовать своё рабочее место.
 
4.2Интерфейс
Таквыглядит окно экземпляра пользовательского приложения «Профилировщик»:

/>
Вверхней части диалога находятся два ниспадающих списка, верхний из которыхотображает список запущенных процессов в системе, а нижний – список потоковэтого процесса. С помощью этих элементов управления можно указать приложению,за каким процессом и каким потоком этого процесса вести наблюдение.
Надиалоге есть три группы:
Группа«Информация о процессе»:
ProcessID– идентификатор процесса;
ParentID– идентификатор процесса-родителя;
BasePriority– базовый приоритет по-умолчанию для потоков процесса;
ThreadCount– количество потоков процесса;
KernelTime– суммарное время, проведённое в режиме ядра потоками процесса, 1 единица равна100 нс;
UserTime- суммарное время, проведённое в пользовательском режиме потоками процесса, 1единица равна 100 нс.
Группа«Информация о потоке»:
ThreadID– идентификатор потока;
BasePriority– базовый приоритет потока;
Priority– приоритет потока;
ContextSwitches– количество переключений контекста, осуществлённых потоком;
KernelTime–время, проведённое в режиме ядра (1 единица равна 100 нс);
UserTime- время, проведённое в пользовательском режиме (1 единица равна 100 нс).
WaitTime– момент времени, когда поток перешёл в состояние ожидания (отсчёт ведётся отмомента запуска системы).
Группа«Контекст потока»:
Здесьпредставлен аппаратный контекст потока. Большинство приложений ожидают ввода отпользователя. При наблюдении за потоками такого процесса можно вообще неувидеть какие-либо изменения. Поэтому для более наглядного просмотра стоитзапускать задачи, требующие больших вычислительных затрат. Например, WinAmp, спомощью которого можно проигрывать музыку – тот поток, который за это отвечает,сразу виден по изменению регистров общего назначения. Но наиболее частыеизменения в регистрах различного назначения происходят в по-настоящему«тяжеловесных» задачах, к примеру, можно взять курсовой проект по Машиннойграфике.
 
4.3Системные требования
Драйвернаписан с расчётом на Windows NT версии 5.x.
Обработказапросов от несколькоих пользовательских приложений-клиентов проверена толькона Windows XP Service Pack 2.

Заключение
Врезультате работы над проектом были реализованы пользовательское приложение,взаимодействующее с Legacy-драйвером. С его помощью оно получает базовуюинформацию о выбранном процессе, базовую информацию и аппаратный контекствыбранного потока указанного процесса. Это приложение является базой дляреализации полноценных профилировщиков приложений для трассировки целевых приложенийи для обнаружения в них узких мест, что может существенно повыситьэффективность труда программиста и разрабатываемого им программногообеспечения.

Списокиспользованной литературы
1.  В.П.Солдатов«Программирование драйверов Windows». Изд. 3-е, перераб. и доп. — М.: ООО«Бином-Пресс», 2006 г. — 576 с.: ил.
2.  М.Руссинович,Д.Соломон «Внутреннее устройство Microsoft Windows: Windows Server 2003,Windows XP и Windows 2000», 4-е издание.
3.  Дж.Рихтер«Windows для профессионалов: создание эффективных Win32 приложений с учетомспецифики 64-разрядной версии Windows»/Пер, англ — 4-е изд. — СПб; Питер; М.:Издательско-торговый дом «Русская Редакция», 2001.
4.  Schreiber,Sven B., 1958-Undocumented Windows 2000 secrets: a programmer's cookbook.
5.  GarryNebbett, Windows NT/2000 Native API.


Не сдавайте скачаную работу преподавателю!
Данный реферат Вы можете использовать для подготовки курсовых проектов.

Поделись с друзьями, за репост + 100 мильонов к студенческой карме :

Пишем реферат самостоятельно:
! Как писать рефераты
Практические рекомендации по написанию студенческих рефератов.
! План реферата Краткий список разделов, отражающий структура и порядок работы над будующим рефератом.
! Введение реферата Вводная часть работы, в которой отражается цель и обозначается список задач.
! Заключение реферата В заключении подводятся итоги, описывается была ли достигнута поставленная цель, каковы результаты.
! Оформление рефератов Методические рекомендации по грамотному оформлению работы по ГОСТ.

Читайте также:
Виды рефератов Какими бывают рефераты по своему назначению и структуре.