Счетчики производительностиWindows поддерживает несколько счетчиков, которые позволяют отслеживать процессы, выполняемые в системе; данные этих счетчиков можно считывать программно или просматривать с помощью оснастки Performance. B таблице 6–3 перечислены счетчики производительности, имеющие отношение к процессам (кроме счетчиков, связанных с управлением памятью и вводом-выводом, которые описываются в главах 7 и 9 соответственно!
Сопутствующие функцииB таблице 6–4 приведена информация по некоторым Windows-функциям, связанным с процессами. Более подробные сведения см. в документации Windows API в MSDN Library.
ЭКСПЕРИМЕНТ: применение команды !process отладчика ядра
Эта команда выводит подмножество информации из блока EPROCESS. Ee вывод для каждого процесса делится на две части. Сначала вы видите часть, показанную ниже (если вы не указываете адрес или идентификатор процесса, команда !process выводит сведения для активного процесса на текущем процессоре).
Вслед за базовой информацией о процессе появляется список его потоков. Данная часть поясняется в эксперименте «Применение команды !thread отладчика ядра» далее в этой главе. Еще одна команда, позволяющая получить информацию о процессе, — !handle. Она создает дамп таблицы описателей, принадлежащей процессу (см. раздел «Описатели объектов и таблица описателей, принадлежащая процессу» главы 3). Структуры защиты процессов и потоков описываются в главе 8.
Что делает функция CreateProcessK этому моменту мы уже рассмотрели структуры, которые являются частью процесса, и API-функции, позволяющие вам (и операционной системе) манипулировать процессами. Вы также научились пользоваться различными утилитами для наблюдения за тем, как процессы взаимодействуют с системой. Ho как эти процессы появляются на свет и как они завершаются, выполнив задачи, для которых они предназначались? B следующих разделах вы узнаете, как порождаются Windows-процессы.
Создание Windows-процесса осуществляется вызовом одной из таких функций, как CreateProcess, CreateProcessAsUser, CreateProcessWithTokenW или CreateProcessWitbLogonW, и проходит в несколько этапов с участием трех компонентов операционной системы: Kernel32.dll (библиотеки клиентской части Windows), исполнительной системы и процесса подсистемы окружения Windows (Csrss). Поскольку архитектура Windows поддерживает несколько подсистем окружения, операции, необходимые для создания объекта «процесс» исполнительной системы (которым могут пользоваться и другие подсистемы окружения), отделены от операций, требуемых для создания Windows-процесса. Поэтому часть действий Windows-функции CreateProcess специфична для семантики, привносимой подсистемой Windows.
B приведенном ниже списке перечислены основные этапы создания процесса Windows-функцией CreateProcess. Детальное описание действий на каждом этапе дается в следующих разделах.
ПРИМЕЧАНИЕ Многие этапы работы CreateProcess связаны с подготовкой виртуального адресного пространства процесса и поэтому требуют понимания массы структур и терминов, связанных с управлением памятью и описываемых в главе 7.
1. Открывается файл образа (EXE), который будет выполняться в процессе.
2. Создается объект «процесс» исполнительной системы.
3. Создается первичный поток (стек, контекст и объект «поток» исполнительной системы).
4. Подсистема Windows уведомляется о создании нового процесса и потока.
5. Начинается выполнение первичного потока (если не указан флаг CREATE_SUSPENDED).
6. B контексте нового процесса и потока инициализируется адресное пространство (например, загружаются требуемые DLL) и начинается выполнение программы.
Общая схема создания процесса в Windows показана на рис. 6–5. Прежде чем открыть исполняемый образ для выполнения, CreateProcess делает следующее.
• При вызове CreateProcess класс приоритета указывается в параметре CreationFlags, и, вызывая CreateProcess, вы можете задать сразу несколько классов приоритета. Windows выбирает самый низкий из них.
• Когда для нового процесса не указывается класс приоритета, по умолчанию принимается Normal, если только класс приоритета процесса-создателя не равен IdIe или Below Normal. B последнем случае новый процесс получает тот же класс приоритета, что и у родительского процесса.
• Если для нового процесса указан класс приоритета Real-time, а создатель не имеет привилегии Increase Scheduling Priority, устанавливается класс приоритета High. Иначе говоря, функция CreateProcess завершается успешно, даже если у того, кто ее вызвал, недостаточно привилегий для создания процессов с классом приоритета Real-time, — просто класс приоритета нового процесса будет ниже Real-time.
• Все окна сопоставляются с объектами «рабочий стол», которые являются графическим представлением рабочего пространства. Если при вызове CreateProcess не указан конкретный объект «рабочий стол», новый процесс сопоставляется с текущим объектом «рабочий стол» процесса-создателя.
Этап 1: открытие образа, подлежащего выполнениюКак показано на рис. 6–6 и в таблице 6–5, на первом этапе CreateProcess должна найти нужный Windows-образ, который будет выполнять файл, указанный вызвавшим процессом, и создать объект «раздел» для его последующего проецирования на адресное пространство нового процесса. Если имя образа не указано, используется первая лексема командной строки (первая часть командной строки, которая заканчивается пробелом или знаком табуляции и является допустимой в качестве имени образа).
B Windows XP и Windows Server 2003 CreateProcess проверяет, не запрещает ли политика безопасности на данной машине запуск этого образа (см. главу 8).
Если в качестве исполняемого файла указана Windows-программа, ее имя используется напрямую. A если исполняемый файл является не Windows-приложением, а программой MS-DOS, Winl6 или POSIX, то CreateProcess ищет образ поддержки (support image) для запуска этой программы. Данный процесс необходим потому, что приложения, не являющиеся Windows-программами, нельзя запускать напрямую. Вместо этого Windows использует один из нескольких специальных образов поддержки, которые и отвечают за запуск приложений, отличных от Windows-программ. Так, если вы пытаетесь запустить POSIX-приложение, CreateProcess идентифицирует его как таковое и вызывает исполняемый Windows-файл поддержки POSIX, Posix.exe. A если вы запускаете программу MS-DOS или Winl6, стартует исполняемый Windows-файл поддержки Ntvdm.exe. Короче говоря, вы не можете напрямую создать процесс, не являющийся Windows-процессом. Если Windows не найдет соответствующий файл поддержки, вызов CreateProcess закончится неудачей.
Конкретное решение о запуске того или иного файла поддержки CreateProcess принимает так.
• Если исполняемый файл — программа MS-DOS с расширением EXE, COM или PIF, подсистеме Windows посылается сообщение, чтобы она проверила, не создан ли уже процесс поддержки MS-DOS (Ntvdm.exe, указанный в параметре реестра HKLM\SYSTEM\CurrentControlSet\Control\WOW\Cmdline). Если да, этот процесс используется для запуска программы MS-DOS — подсистема Windows посылает виртуальной DOS-машине (Virtual DOS Machine, VDM) сообщение для запуска новой программы, — после чего управление возвращается к CreateProcess. Если нет, запускается Ntvdm.exe и повторно выполняется первый этап CreateProcess.
• Если исполняемый файл — командный файл с расширением BAT или CMD, запускается Cmd.exe, обрабатывающий командную строку Windows, и повторно выполняется первый этап CreateProcess. (Имя командного файла передается Cmd.exe как первый параметр.)
• Если исполняемый файл — приложение Winl6 (Windows 3.1), CreateProcess решает, надо ли для его запуска создавать новый процесс VDM или оно должно использовать глобальный для всех сеансов процесс VDM (который, возможно, еще не создан). Решение определяется флагами CREATE_SEPARATE_WOW_VDM и CREATE_SHARED_WOW_VDM. Если эти флаги не заданы, то по умолчанию решение принимается, исходя из значения параметра реестра HKLM\SYSTEM\CurrentControlSet\Control\WOW\DefaultSeparateVDM. Если программа будет работать в отдельной VDM, запускается приложение, указанное в HKLM\SYSTEM\CurrentControlSet\Control\WOW\WowCmdline, и повторно выполняется первый этап CreateProcess. B ином случае подсистема Windows посылает сообщение для проверки возможности использования общего процесса VDM. (Это исключено, если процесс VDM сопоставлен с другим объектом «рабочий стол» или если его параметры защиты отличны от таковых для вызывающего процесса. Тогда нужно создавать новый процесс VDM.) Если задействовать общий процесс VDM нельзя, подсистема Windows посылает ему сообщение о необходимости запуска нового образа, и управление возвращается к CreateProcess. Если процесс VDM еще не создан (или если он существует, но использовать его нельзя), запускается образ поддержки VDM и повторно выполняется первый этап CreateProcess. K этому моменту CreateProcess успешно открывает допустимый исполняемый файл Windows и создает для него объект «раздел». Этот объект еще не спроецирован на память, но уже открыт. Однако сам факт успешного создания объекта «раздел» не означает того, что запускаемый файл является допустимым Windows-образом, — он может быть DLL или исполняемым файлом POSIX. Если это исполняемый файл POSIX, запускается Posix.exe, и CreateProcess заново выполняет действия первого этапа. A если это DLL, вызов CreateProcess заканчивается неудачей.
CreateProcess, найдя допустимый исполняемый Windows-образ, ищет в разделе реестра HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options подраздел с именем и расширением запускаемого образа (но без указания пути к нему, например Image.exe). Если такой подраздел есть, CreateProcess ищет в нем параметр Debugger. Если он присутствует, его значение становится именем запускаемого образа, после чего следует повторение первого этапа CreateProcess.
СОВЕТ Вы можете извлечь выгоду из такого поведения CreateProcess. Оно позволяет отлаживать стартовый код процессов сервисов Windows перед их запуском. Если бы вы подключили отладчик лишь после запуска сервиса, это исключило бы возможность отладки стартового кода.
Этап 2: создание объекта «процесс»K началу второго этапа функция CreateProcess уже открыла допустимый исполняемый файл Windows и создала объект «раздел» для его проецирования на адресное пространство нового процесса. После этого она создает объект «процесс», чтобы запустить образ вызовом внутренней функции NtCreateProcess. Создание объекта «процесс» исполнительной системы включает следующие подэтапы:
• формируется блок EPROCESS;
• создается начальное адресное пространство процесса; • инициализируется блок процесса ядра (KPROCESS);
• инициализируется адресное пространство процесса (в том числе список рабочего набора и дескрипторы виртуального адресного пространства), а также проецируется образ на это пространство;
• формируется блок РЕВ;
• завершается инициализация объекта «процесс» исполнительной системы.
ПРИМЕЧАНИЕ Родительские процессы отсутствуют только при инициализации системы. Далее они всегда используются для задания контекстов защиты новых процессов.
Этап 2A: формирование блока EPROCESSЭтот подэтап включает девять операций.
1. Создается и инициализируется блок EPROCESS.
2. От родительского процесса наследуется маска привязки к процессорам.
3. Минимальный и максимальный размеры рабочего набора процесса устанавливаются равными значениям переменных PsMinimumWorkingSet и PsMaximumWorkingSet.
4. Блок квот нового процесса настраивается на адрес блока квот его родительского процесса и увеличивается счетчик ссылок на блок квот последнего.
5. Наследуется пространство имен устройств Windows (в том числе определение букв дисков, СОМ-портов и т. д.).
6. B поле InheritedFromUniqueProcessId нового объекта «процесс» сохраняется идентификатор родительского процесса.
7. Создается основной маркер доступа процесса (копированием аналогичного маркера родительского процесса). Новый процесс наследует профиль защиты своих родителей. Если используется функция CreateProcessAsUser, чтобы задать для нового процесса другой маркер доступа, он соответственно модифицируется.
8. Инициализируется таблица описателей, принадлежащая процессу. Если установлен флаг наследования описателей родительского процесса, наследуемые описатели из его таблицы копируются в новый процесс (о таблицах описателей см. главу 3).
9. Статус завершения нового процесса устанавливается как STATUSPENDING.
Этап 2B: создание начального адресного пространства процессаНачальное адресное пространство процесса состоит из следующих страниц:
• каталога страниц (этих каталогов может быть больше одного в системах, где таблицы страниц имеют более двух уровней, например в х86-систе-мах в режиме PAE или в 64-разрядных системах);
• страницы гиперпространства;
• списка рабочего набора.
Для создания этих страниц выполняются операции, перечисленные ниже.
1. B соответствующих таблицах страниц формируются записи, позволяющие проецировать эти начальные страницы. Количество страниц вычитается из переменной ядра MmTotalCommittedPages и добавляется к переменной ядра MmProcessCommit.
2. Из MmResidentAvailablePages вычитается минимальный размер рабочего набора по умолчанию (PsMinimumWorkingSef).
3. Ha адресное пространство процесса проецируются страницы таблицы страниц для неподкачиваемой части системного пространства и системного кэша.
Этап 2C: создание блока процесса ядраHa этом подэтапе работы CreateProcess инициализируется блок KPROCESS, содержащий указатель на список потоков ядра. (Ядро не имеет представления об описателях, поэтому оно обходит их таблицу.) Блок процесса ядра также указывает на каталог таблицы страниц процесса (используемый для отслеживания виртуального адресного пространства процесса) и содержит суммарное время выполнения потоков процесса, базовый приоритет процесса по умолчанию (он начинается с Normal, или 8, если только его значение у родительского процесса не равно IdIe или Below Normal; в последнем случае приоритет просто наследуется), привязку потоков к процессорам по умолчанию и начальный квант процессорного времени, выделяемый процессу по умолчанию. Последнее значение принимается равным PspForegroundQuantum[0], первому элементу общесистемной таблицы величин квантов.
ПРИМЕЧАНИЕ Начальный квант по умолчанию в клиентских и серверных версиях Windows неодинаков. Подробнее о квантах см. раздел «Планирование потоков» далее в этой главе.
Этап 2D: инициализация адресного пространства процессаПодготовка адресного пространства нового процесса довольно сложна, поэтому разберем ее отдельно по каждой операции. Для максимального усвоения материала этого раздела вы должны иметь представление о внутреннем устройстве диспетчера памяти Windows (см. главу 7).
• Диспетчер виртуальной памяти присваивает времени последнего усечения (last trim time) для процесса текущее время. Диспетчер рабочих наборов, выполняемый в контексте системного потока диспетчера настройки баланса (balance set manager), использует это значение, чтобы определить, когда нужно инициировать усечение рабочего набора.
• Диспетчер памяти инициализирует список рабочего набора процесса, после чего становится возможной генерация ошибок страниц.
• Раздел (созданный при открытии файла образа) проецируется на адресное пространство нового процесса, и базовый адрес раздела процесса приравнивается базовому адресу образа.
• Ha адресное пространство процесса проецируется Ntdll.dll.
• Ha адресное пространство процесса проецируются общесистемные таблицы NLS (national language support).
ПРИМЕЧАНИЕ Процессы POSIX клонируют адресное пространство своих родителей, поэтому для них не нужны все вышеперечисленные операции создания нового адресного пространства. B случае приложений POSIX базовый адрес раздела нового процесса приравнивается тому же базовому адресу родительского процесса, а родительский PEB просто копируется.
Этап 2E: формирование блока PEBCreateProcess выделяет страницу под PEB и инициализирует некоторые поля, описанные в таблице 6–6.