Вятский государственный гуманитарный университет
Опубликован: 27.05.2013 | Доступ: свободный | Студентов: 2689 / 585 | Длительность: 09:18:00
Самостоятельная работа 3:

Задания по планированию потоков

< Лекция 7 || Самостоятельная работа 3: 123 || Лекция 8 >

Задание 7. Исследовать очередь потоков для выполнения.

Указания к выполнению.

1. Скачайте утилиту CPUSTRES от Sysinternals по адресу: http://live.sysinternals.com/WindowsInternals/.

2. В виртуальной машине запустите утилиту CPUSTRES.

Выберите значения полей утилиты так, как показано на рисунке:


Важно обеспечить загрузку системы несколькими потоками, желательно с разными приоритетами.

3. Прервите выполнение виртуальной машины в отладчике (Ctrl+Break).

4. Определите адрес структуры KPRCB (см. предыдущее задание). Предположим, адрес структуры KPRCB равен FFDFF120.

5. Выведите на экран значения полей структуры KPRCB при помощи команды:

dt nt!_kprcb FFDFF120

6. Найдите поля ReadySummary и DispatcherReadyListHead (см. лекцию 9 "Планирование потоков", раздел "Алгоритмы планирования в Windows"):

7.


8. Поле ReadySummary показывает приоритеты, для которых имеются готовые к выполнению потоки.

Предположим, поле ReadySummary = 0x381. Переведем это значение как 32 разрядное число в двоичный вид:


Двоичные единицы в этом поле обозначают приоритеты, для которых в данный момент имеются очереди готовых потоков.

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

9. Поле DispatcherReadyListHead указывает на очереди готовых потоков.

Данное поле представляет собой массив элементов типа LIST_ENTRY (см. файл public\sdk\inc\ntdef.h, строка 1084). Размерность массива совпадает с количеством приоритетов в системе – 32.

Чтобы просмотреть содержимое массива, введите в отладчике следующую команду:

dd FFDFF120+9F0

Адрес получается путем прибавления смещения поля DispatcherReadyListHead (9F0) к стартовому адресу структуры KPRCB (FFDFF120).


Тип LIST_ENTRY описывает двунаправленный список и представляет собой структуру, состоящую из двух полей: Flink (Forward Link) – указатель на следующий элемент списка и Blink (Backward Link) – указатель на предыдущий элемент списка.

На рисунке показаны первые 16 элементов массива DispatcherReadyListHead и обведены разные структуры LIST_ENTRY, представляющие элементы массива и состоящие из двух адресов – Flink и Blink.

Большинство элементов массива описывают пустые списки – это ситуация, когда адреса в обоих полях структуры LIST_ENTRY совпадают и указывают на одно и то же поле – Flink. Например, на рисунке первый элемент массива представляет собой структуру LIST_ENTRY, располагающуюся по адресу FFDFFB18, оба поля которой содержат тот же самый адрес.

Нас интересуют непустые списки – это нулевой, седьмой, восьмой и девятый элементы массива (см. единичные биты в поле ReadySummary). Рассмотрим девятый элемент массива, описывающий очередь готовых потоков с максимальным в данный момент приоритетом. Заметим, что он расположен по адресу FFDFFB58.

Для девятого элемента поле Flink = 81F454C0, поле Blink = 82258570.

Посмотрим, что располагается в памяти по адресу, на который указывает Flink:


По этому адресу располагается структура LIST_ENTRY, первое поле которой (Flink) указывает на следующий элемент списка, а второе поле (Blink) – на предыдущий элемент.

Пройдем дальше, к следующему элементу списка:


Очевидно, это последний элемент списка, поскольку первое поле Flink указывает на адрес FFDFFB58 – начало списка.

Таким образом, схема расположения списка готовых потоков с приоритетом 9 будет выглядеть следующим образом:


Рассмотрим сейчас, каким образом определить потоки, на которые указывают элементы данного списка.

В списке три элемента: первый элемент по адресу FFDFFB58 является частью структуры KPRCB, второй и третий элементы представляют собой поле WaitListEntry структуры KTHREAD (см. файл base\ntos\inc\ke.h, строка 1128). Данное поле располагается по смещению 0x060 относительно начала структуры KTHREAD, это можно узнать, введя команду:

dt kthread

Таким образом, чтобы узнать адрес начала структуры KTHREAD потока в очереди готовых потоков, нужно из адреса, по которому располагается элемент списка очереди, вычесть 0x060.

Выведем на экран структуру KTHREAD для первого потока в очереди потоков. Адрес соответствующего элемента списка равен 81F454C0, поэтому используем команду:

dt kthread 81F454C0–60

Чтобы узнать процесс, к которому принадлежит данный поток, найдем поле Process структуры KTHREAD:


Обратите внимание на поле BasePriority – там указан приоритет 9, который совпадает с приоритетом очереди потоков.

В поле Process указан адрес структуры KPROCESS (поля Pcb) процесса, которому принадлежит данный поток. Поскольку поле Pcb является первым в структуре EPROCESS (нулевое смещение), то адрес структуры KPROCESS совпадает с адресом структуры EPROCESS процесса.

Выведем на экран структуру EPROCESS по найденному адресу и узнаем имя исполняемого образа по полю ImageFileName:


Как видно из рисунка, поток, находящийся первым в очереди готовых потоков с приоритетом 9, принадлежит процессу CPUSTRES.EXE. Именно этот поток в данный момент будет выбран на выполнение.

Аналогичным образом можно определить процессы-владельцы остальных потоков в очереди.

Задания для самостоятельного выполнения

Задание 1. Исследуйте функцию KeSetQuantumProcess.

Указания к выполнению.

1. Установите в отладчике точку останова на функции KeSetQuantumProcess:

bp nt!KeSetQuantumProcess

2. Измените величину кванта в системе Windows Server 2003 SP1 так, как это описано в задании 3 основной части лабораторной работы.

Задание 2. Определить базовый приоритет какого-либо потока, принадлежащего процессу explorer.exe.

Указания к выполнению.

  1. Базовый приоритет потока хранится в поле BasePriority, а текущий – в поле Priority структуры KTHREAD.
  2. Также приоритет потока отображается при выполнении команды !thread.
  3. Ещё один способ узнать приоритет потока – с помощью утилиты Process Explorer.

Задание 3. Изменить базовый приоритет потока.

Указания к выполнению.

1. Приоритет потока можно изменить программным путем. Например, утилита CPUSTRES от Sysinternals предоставляет возможность запустить несколько потоков с разными приоритетами.

2. Запустите утилиту CPUSTRES. Посмотрите в отладчике приоритеты её потоков. Измените приоритет потока в CPUSTRES и проверьте, что в отладчике значение также изменилось.

3. Более сложный вариант задания – написать программу, изменяющую приоритет собственных потоков. См. WinAPI функцию SetThreadPriority.

Задание 4. Исследовать функцию KiQuantumEnd.

Указания к выполнению.

1. Установите в отладчике точку останова на функции KiQuantumEnd (см. лабораторную работу 2 "Процессы и потоки", задание 4).

Для этого прервите выполнение виртуальной машины (Ctrl+Break) и воспользуйтесь следующей командой:

bp nt!KiQuantumEnd

2. Продолжите выполнение виртуальной машины (F5). Почти сразу после этого выполнение должно прерваться и управление перейдет в отладчик на функцию KiQuantumEnd (сработает точка останова).

3. Выполните трассировку функции KiQuantumEnd.

< Лекция 7 || Самостоятельная работа 3: 123 || Лекция 8 >