Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Создание эффективных приложений для Windows Джеффри Рихтер 2004 (Книга).pdf
Скачиваний:
375
Добавлен:
15.06.2014
Размер:
8.44 Mб
Скачать

typedef struct _JOBOBJECT_SECURITY_LIMIT_INFORMATION

{

DWORD SecurityLimitFlags; HANDLE JobToken;

PTOKEN GROUPS SidsToDisable; PTOKEN_PRIVILEGES PrivilegesToDelete; PTOKEN_GROUPS RestrictedSids;

} JOBOBJECT_SECURITY LIMIT_INFORMATION,

*PJOBOBJECT_SECURITY_LIMIT_INFORMATION;

Ее элементы описаны в следующей таблице

Элемент

Описание

 

 

SecurityLimitFlags

Набор флагов, которые закрывают доступ администратору, запре щают маркер

 

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

 

блокируют доступ по каким-либо иден тификаторам защиты (security ID, SID)

 

и отменяют указанные при вилегии

JobToken

Маркер доступа, связываемый со всеми процессами в задании

 

 

SidsToDisable

Указывает, по каким SID не разрешается доступ

 

 

PrivilegesToDelete

Определяет привилегии, которые снимаются с маркера доступа

 

 

RestrictedSids

Задает набор SID, по которым запрещается доступ к любому защи щенному

 

объекту (deny-only SIDs); этот набор добавляется к марке ру доступа

 

 

Естественно, если Вы налагаете ограничения, то потом Вам, наверное, понадобится информация о них. Для этого вызовите:

BOOL QueryInformationJobObject( HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass. PVOID pvJobObjectInformation, DWORD cbJobObjectInformationLength, PDWORD pdwReturnLength);

В эту функцию, как и в SetInformationJobObject, передается описатель задания, пе ременная перечислимого типа JOBOJECTINFOCLASS. Она сообщает информацию об ограничениях, адрес и размер структуры данных, инициализируемой функцией. Пос ледний параметр, pdwReturnLength, заполняется самой функцией и указывает, сколь ко байтов помещено в буфер Если эти сведения Вас не интересуют (что обычно и бывает), передавайте в этом параметре NULL.

NOTE:

Процесс может получить информацию о своем задании, передав при вызове QuerylnformationJobObject вместо описателя задания значение NULL, Это позво лит ему выяснить установленные для него ограничения Однако аналогичный вызов SetInformationJobOtject даст ошибку, так как процесс не имеет права са мостоятельно изменять заданные для него ограничения

Включение процесса в задание

О'кэй, с ограничениями па этом закончим Вернемся к StartRestrictedProcess. Устано вив ограничения для задания, я вызываю CreateProcess и создаю процесс, который помещаю в это задание. Я использую здесь флаг CREATE_SUSPENDED, и он приводит к тому, что процесс порождается, но код пока не выполняет. Поскольку StartRestricted Process вызывается из процесса, внешнего по отношению к заданию, его дочерний

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

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

BOOL AssignProcessToJobObject( HANDLE hJob, HANDLE hProcess);

Эта функция заставляет систему рассматривать процесс, идентифицируемый па раметром hProcess, как часть существующего задания, на которое указывает hJob. Об ратите внимание, что AssignProcessToJobObject позволяет включить в задание только тот процесс, который еще не относится ни к одному заданию. Как только процесс стал частью какого-нибудь задания, его нельзя переместить в другое задание или отпус тить на волю. Кроме того, когда процесс, включенный в задание, порождает новый процесс, последний автоматически помещается в то же задание. Однако этот поря док можно изменить.

Включая в LimitFlags структуры JOBOBJECT_BASIC_LIMIT_INFORMATION

флаг JOB_OBJECT_BREAKAWAY_OK, Вы сообщаете системе, что новый процесс мо жет выполняться вне задания. Потом Вы должны вызвать CreateProcess с новым флагом CREATE_BREAKAWAY_FROM_TOB. (Если Вы сделаете это без флага

JOB_OBJECT_BREAKAWAY_OK в LimitFlags, функция CreateProcess завершится с ошибкой.) Такой механизм пригодится на случай, если новый процесс тоже управляет заданиями.

Включая в LimitFlags структуры JOBOBJECT_BASIC_LIMIT_INFORMATION флаг JOB_OBJECT_SILENT_BREAKAWAY_OK, Вы тоже сообщаете системе, что новый процесс не является частью задания, Но указывать в CreateProcess какиелибо флаги на этот раз не потребуется. Данный механизм полезен для процессов, которым ничего не известно об объектах-заданиях.

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

Завершение всех процессов в задании

Уверен, именно это Вы и будете делать чаще всего. В начале главы я упомянул о том, как непросто остановить сборку в Developer Studio, потому что для этого ему должны быть известны все процессы, которые успел создать его самый первый процесс. (Это очень каверзная задача. Как Developer Studio справляется с ней, я объяснял в своей колонке «Вопросы и ответы по Win32» в июньском выпуске Microsoft Systems Journal за 1998 год.) Подозреваю, что следующие версии Developer Studio будут использовать механизм заданий, и решать задачу, о которой мы с Вами говорили, станет гораздо легче.

Чтобы уничтожить все процессы в задании, Вы просто вызываете

BOOL TerminateJobOb]ect( HANDLE hJob, UINT uExitCode);

Вызов этой функции похож на вызов TerminateProcessw для каждого процесса в за дании и присвоение всем кодам завершения одного значения — uExitCode.

Получение статистической информации о задании

Мы уже обсудили, как с помощью QueryInformationJobObject получить информацию о текущих ограничениях, установленных для задания. Этой функцией можно пользо ваться и для получения статистической информации. Например, чтобы выяснить ба зовые учетные сведения, вызовите ее, передав JobObjeсtBasicAccountingInformation во втором параметре и адрес структуры JOBOBJECT_BASIC_ACCOUNTING_INFORMATION:

typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION

{

LARGE_INTEGER TotalUserTime; LARGE_INTEGER TotalKernelTime; LARGE_INTEGER ThisPeriodTotalUserTime; LARGE_INTEGER ThisPeriodTotalKernelTime; DWORD TotalPageFaultCount;

DWORD TotalProcesses;

DWORD ActiveProcesses;

DWORD TotalTerminatedProcesses;

} JOBOBJECT_BASIC_ACCOUNTING_INFORMATION, *PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION;

Элементы этой структуры кратко описаны в таблице 5-3

Элемент

Описание

 

 

TotalUserTtme

Процессорное время, израсходованное процессами задания в

 

пользовательском режиме

 

 

TotalKernelTime

Процессорное время, израсходованное процессами задания в режиме ядра

 

 

ThisPeriodTotalUserTime

То же, что TotalUserTime, но обнуляется, когда базовые oгpa ничения

 

изменяются вызовом SetIniformationJobObject, а флаг JOB

 

OBJECT_LIMIT_PRESERVE_JOB_TIME не используется

 

 

ThisPeriodTotalKernelTime

То же, что ThisPeriodTotalUserTime, но относится к процессор ному

 

времени, израсходованному в режиме ядра

 

 

TotalPageFaultCount

Общее количество ошибок страниц, вызванных процессами задания

 

 

TotalProcesses

Общее число процессов, когда-либо выполнявшихся в зтом задании

 

 

ActiveProcesses

Текущее количество процессов в задании

 

 

TotalTermtnatedProcesses

Количество процессов, завершенных из-за превышения ими отведенного

 

лимита процессорного времени

 

 

Таблица 5-3. Элементы структуры JOBOBJECT_BASIC_ACCOUNTING_INFORMATION

Вы можете извлечь те же сведения вместе с учетной информацией по вводу-выво ду,

передав JobObjectBasicAndIoAccountingInformation во втором параметре и адрес структуры

JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION:

typedef struct JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION

{

JOBOBJECT_BASIC_ACCOUNTING_TNFORMATION Basiclnto; IO_COUNTERS IoInfo;

} JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION;

Как видите, она просто возвращает JOBOBJECT_BASIC_ACCOUNTlNG_INFORMA

TION и IO_COUNTERS. Последняя структура показана на следующей странице

typedef struct _IO_COUNTERS

{

ULONGlONG ReadOperationCount;

ULONGLONG WriteOperationCount;

ULONGLONG OtherOperationCount;

ULONGLONG ReadTransferCount;

ULONGLONG WriteTransferCount;

ULONGLONG OtheiTransferCount;

} IO_COUNTERS;

Она сообщает о числе операций чтения, записи и перемещения (а также о коли честве байтов, переданных при выполнении этих операций) Данные относятся ко всем процессам в задании Кстати, новая функция GetProcessIoCounters позволяет по лучить ту же информацию о процессах, не входящих ни в какие задания

BOOL GetProcessIoCounters( HANDLE hProcess, PIO_GOUNTERS pToCounters);

QueryInformationJobObject такжe возвращает набор идентификаторов текущих про цессов в задании Но перед этим Вы должны прикинуть, сколько их там может быть, и выделить соответствующий блок памяти, где поместятся массив идентификаторов и структура

JOBOBJECT_BASIC_PROCESS_ID_LIST

typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST

{

DWORD NumberOfAssigncdProcessps;

DWORD NurrberOfProcessIdsInList; DWORD ProcessIdList[1];

} JOBOBJECT_BASIC_PROCESS_ID_LIST,

*PJOBOBJECT_BASIC_PROCESS_ID_LIST ;

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

void EnumProcessIdsInJob(HANDLE hjob)

{

//я исхожу из того, что количество процессов

//в этом задании никогда не превысит 10

#define MAX_PROCESS_TDS 10

//определяем размер блока памяти (в байтах)

//для хранения идентификаторов и структуры

DWORD cb = sizeof(JOBOBJECT_BASlC_PROCESS_ID LIST) + (MAX_PROCESS_IDS - 1) * sizeof(DWORD);

// выделяем этот блок памяти

PJOBOBJECT_BASIC_PROCESS_ID_LIST pjobpil = _alloca(cb);

//сообщаем функции, на какое максимальное число процессов

//рассчитана выделенная нами память pjobpil- >NumberOfAssignedProcesseb = MAX_PROCESS_IDS;

//запрашиваем текущий список идентификаторов процессов

QuerylnformationJobObject(hjob, JobObjectBasicProcessIdList pjobpil, cb &cb);

//перечисляем идентификаторы процессов

for (int x =- 0; x < pjobpil->NumberOfProcessIdsInList; x++)

{

// используем pjobpil->ProcessIdList[x]

}

//так как для выделения памяти мы вызывали _alloca,

//освобождать память нам не потребуется

}

Вот и все, что Вам удастся получить через эти функции, хотя на самом деле опе рационная система знает о заданиях гораздо больше. Эту информацию, которая хра нится в специальных счетчиках, можно извлечь с помощью функций из библиотеки Performance Data Helper (PDH dIl) или через модуль Performance Monitor, подключае мый к Microsoft Management Console (MMC) Рис 5-3 иллюстрирует некоторые из доступных в системе счетчиков заданий (job object counters), а рис. 5-4 — счетчики, относящиеся к отдельным параметрам заданий (job object details counters) Заметьте, что в чадании Jeff содержится четыре процесса calc, cmd, notepad и wordpad.

Рис. 5-3. MMC Performance Monitor счетчики задания