48429 (Профилировщик приложений), страница 3

2016-07-30СтудИзба

Описание файла

Документ из архива "Профилировщик приложений", который расположен в категории "". Всё это находится в предмете "информатика" из 1 семестр, которые можно найти в файловом архиве . Не смотря на прямую связь этого архива с , его также можно найти и в других разделах. Архив можно найти в разделе "курсовые/домашние работы", в предмете "информатика, программирование" в общих файлах.

Онлайн просмотр документа "48429"

Текст 3 страницы из документа "48429"

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

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

3.1.3 DispatchCreate и DispatchClose

В этих функциях происходит учёт количества открытых описателей данного драйвера полученных с помощью API-вызова CreateFile(). Сколько описателей было открыто – столько же должно быть закрыто API-вызовом CloseHandle(). Иначе драйвер по окончании работы пользовательского приложения останется в операционной системе, что, естественно, крайне не желательно.

3.1.4 DispatchDeviceControl

Эта процедура обслуживает IOCTL-запросы от пользовательских приложений посылаемые API-вызовом DeviceIoControl(). В данном курсовом проекте взаимодействие с драйвером большею частью и построено на их применении, здесь реализована основная функциональность драйвера: то, для чего он и предназначался. Поэтому данная процедура наиболее объёмна.

Сначала, назависимо от конкретного IOCTL-запроса, получается указатель на ячейку IRP-стека IRP-пакета, предназначенную для объекта устройства драйвера:

PIO_STACK_LOCATION pIrpStack = 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:

BOOL DeviceIoControl

(HANDLE hDevice,

DWORD dwIoControlCode,

LPVOID lpInBuffer, DWORD nInBufferSize,

LPVOID lpOutBuffer, DWORD nOutBufferSize,

LPDWORD lpBytesReturned,

LPOVERLAPPED lpOverlapped);

HANDLE hDevice – описатель устройства, которому посылается запрос;

DWORD dwIoControlCode – код IOCTL-запроса;

LPVOID lpInBuffer – адрес входного буфера;

DWORD nInBufferSize – длина входного буфера;

LPVOID lpOutBuffer – адрес выходного буфера;

DWORD nOutBufferSize - длина выходного буфера;

LPDWORD lpBytesReturned – количество переданных байтов;

LPOVERLAPPED lpOverlapped – структура, необходимая при использовании асинхронного выполнения запроса, чего нет в данном приложении.

Использование этого API-вызова полностью инкапсулировано в классе CDriver, в котором для выполнения каждого запроса реализован отдельный метод с именем, близким к названию IOCTL-запроса, что обеспечивает интуитивное понимание интерфейса этого класса.

Также этот класс инкапсулирует в себя использование Менеджера управления сервисами (SCM - Service Control Manager), с помощью которого осуществляется динамическая установка, запуск, останов и удаление драйвера.



4. Технический раздел

4.1 Выбор операционной системы и среды программирования

В качестве операционной системы была выбрана система Widows. Это обусловлено тем, что операционная система DOS уже устарела в силу многих причин (мы уже ушли от ОС, работающих в однозадачном режиме), а других операционных систем для персональных машин с хорошим интерфейсом, действительно удобных для пользователя, еще нет. Windows по прежнему остается самой распространенной ОС для ПК. Кроме того различные среды разработки программных продуктов разработаны именно под Windows:

Visual C++, Visual Basic, Borland C++ Builder, Delphi и другие.

Языком написания пользовательской программы был выбран С++. Язык С++ дает очень богатые возможности для программистов и, пожалуй является наиболее распространенным в их среде. Это очень мощный операторный язык. Кроме того, он обеспечивает достаточную свободу в написании программ, в то время как Pascal ставит очень узкие рамки, в частности, в описании переменных и не дает возможности построения сложных операторных выражений. Языком написания драйвера был выбран С. Применение этого языка обеспечивает переносимость меджу системами: максимум, что придётся сделать – это пересобрать драйвер. В качестве среды разработки была выбрана Microsoft Visual Studio .Net, поскольку она дает мощные и удобные средства не только визуальной разработки интерфейса программного продукта, но и настройки проектов, что позволяет эффективно организовать своё рабочее место.

4.2 Интерфейс

Так выглядит окно экземпляра пользовательского приложения «Профилировщик»:

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

На диалоге есть три группы:

Группа «Информация о процессе»:

ProcessID – идентификатор процесса;

ParentID – идентификатор процесса-родителя;

BasePriority – базовый приоритет по-умолчанию для потоков процесса;

ThreadCount – количество потоков процесса;

KernelTime – суммарное время, проведённое в режиме ядра потоками процесса, 1 единица равна 100 нс;

UserTime - суммарное время, проведённое в пользовательском режиме потоками процесса, 1 единица равна 100 нс.

Группа «Информация о потоке»:

ThreadID – идентификатор потока;

Свежие статьи
Популярно сейчас
Зачем заказывать выполнение своего задания, если оно уже было выполнено много много раз? Его можно просто купить или даже скачать бесплатно на СтудИзбе. Найдите нужный учебный материал у нас!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Нет! Мы не выполняем работы на заказ, однако Вы можете попросить что-то выложить в наших социальных сетях.
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
4121
Авторов
на СтудИзбе
667
Средний доход
с одного платного файла
Обучение Подробнее