Мегаобучалка Главная | О нас | Обратная связь


Учет пользователей объектов ядра



2016-01-02 835 Обсуждений (0)
Учет пользователей объектов ядра 0.00 из 5.00 0 оценок




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

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

 

2. Создание процессов. Параметры функции CreateProcess().

Создание процессов

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

которая имеет следующий прототип:

BOOL CreateProcess(

LPCTSTR lpApplicationName, // имя исполняемого модуля

LPTSTR lpCoramandLine, // командная строка

LPSECURITY_ATTRIBUTES lpProcessAttributes, // защита процесса

LPSECURITY_ATTRIBUTES lpThreadAttributes, // защита потока

BOOL bInheritHandles, // признак наследования дескриптора

DWORD dwCreationFlags, // флаги создания процесса

LPVOID lpEnvironment, // блок новой среды окружения

LPCTSTR lpCurrentDirectory, // текущий каталог

LPSTARTUPINFO lpStartUpInfo, // вид главного окна

LPPROCESS_INFORMATION lpProcessInformation // информация о

// процессе );

Функция CreateProcess возвращает TRUE, если процесс и поток были

успешно созданы, или FALSE при неудаче. Процесс, который создает новый

процесс, называется родительским процессом (parent process). Новый же

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

процессом (child process). Опишем назначение некоторых параметров функции

CreateProcess. Первый параметр lpApplicationName определяет строку с именем

исполняемого файла, который имеет тип ехе и будет запускаться при создании

нового процесса. Эта строка должна заканчиваться нулем и содержать полный

путь к исполняемому файлу. Возвращаемое значение:

При использовании параметра lpCommandLine система для запуска

нового процесса осуществляет поиск требуемого ехе-файла в следующей

последовательности каталогов:

- каталог, из которого запущено приложение;

- текущий каталог родительского процесса;

- системный каталог Windows;

- каталог Windows;

- каталоги, которые перечислены в переменной PATH среды окружения.

Параметры lpProcessAttributes и lpThreadAttributes указывают на структуры

атрибутов безопасности процесса и потока. В случае если их значение NULL,

используются атрибуты по умолчанию.

Параметр bInheritHandles определяет, должен ли новый процесс наследовать

копии открытых наследуемых дескрипторов (файлов, отображений и т.д.)

процесса, вызвавшего функцию. Унаследованные дескрипторы имеют те же

атрибуты, что и их оригиналы.

В параметре dwCreationFlags можно объединять несколько флагов.

• CREATE_SUSPENDED — первичный поток находится в состоянии ожидания

и будет запущен только после вызова функции ResumeThread.

• DETACHED_PROCESS и CREATE_NEW_CONSOLE —

взаимоисключающие флаги; нельзя установить оба сразу. Первый флаг создает

процесс без консоли, а второй предоставляет консоль новому процессу. Если ни

один из этих флагов не установлен, процесс наследует консоль родителя.

• CREATE_NEW_PROCESS_GROUP определяет новый процесс как корневой

для новой группы процессов. Если процессы группы совместно используют

одну консоль, то все они получают сигнал управления консолью.

Некоторые флаги управляют приоритетом потоков нового процесса. Пока

просто будем использовать приоритет родительского процесса (не указывая

ничего) или значение NORMAL_PRIORITY_CLASS.

lpEnvironment указывает блок окружения для нового процесса. Если пара-

метр имеет значение NULL, то используется окружение родительского

процесса.

lpCurrentDirectory определяет диск и каталог для нового процесса. Если его

значение NULL, то будет использован рабочий каталог родительского

процесса.

lpStartUpInfo указывает вид основного окна программы и дескрипторы стан-

дартных устройств для нового процесса.

Параметр lpProcessInformation определяет структуру, в которую будут

помещены дескрипторы и идентификаторы для созданных процесса и потока.

Структура PROCESS_INFORMATION определена так:

typedef struct _PROCESS_INFORMATION { HANDLE hProcess;

HANDLE hThread; DWORD dwProcessID; DWORD dwThreadID;

} PROCESS_INFORMATION;

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

Процесс может завершить свою работу вызовом функции ExitProcess,

которая имеет следующий прототип:

VOID ExitProcess(

UINT uExitCode // код возврата из процесса );

При вызове функции ExitProcess завершаются все потоки процесса с кодом

возврата, который является параметром этой функции. При выполнении этой

функции система посылает динамическим библиотекам, которые загружены

процессом, сообщение DLL_PROCESS_DETACH, которое говорит о том, что

динамическую библиотеку необходимо отсоединить от процесса.

Один процесс может быть завершен другим при помощи вызова функции

TerminateProcess, которая имеет следующий прототип:

BOOL TerminateProcess(

HANDLE hProcess, // дескриптор процесса

UINT uExitCode // код возврата );

Если функция TerminateProcess выполнилась успешно, то она возвращает

ненулевое значение, иначе - FALSE. Функция TerminateProcess завершает

работу процесса, но нe ocвoбождает все ресурсы, принадлежащие этому

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

Идентификация процессов

Процесс может получить идентификатор и дескриптор нового дочернего

процесса из структуры PROCESS_INFORMATION. Закрытие дескриптора

дочернего процесса уничтожает только возможность доступа к нему

родительского процесса. Для получения описания текущего процесса используется пара функций.

HANDLE GetCurrentProcess (VOID)

DWORD GetCurrentProcessId (VOID)

Функция GetCurrentProcess в действительности возвращает

псевдодескриптор, который не может быть унаследован. Это значение

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

Создавайте настоящий дескриптор процесса из его ID, используя в вызове

функции OpenProcess значение, возвращенное функцией

GetCurrentProcessId.

HANDLE OpenProcess ( DWORD fdwAccess, BOOL fInherit,

DWORD IDProcess)

Возвращаемое значение: дескриптор процесса или NULL в случае

ошибки.

Параметр fdwAccess определяет параметры доступа процесса к дескриптору.

Приведем некоторые из его возможных значений.

• Флаг SYNCHRONIZE разрешает другим процессам ждать завершения

этого процесса, используя функции ожидания

• PROCESS_ALL_ACCESS — установлены все флаги доступа.

• Флаг PROCESS_TERMINATE делает возможным завершение процесса

вызовом функции TerminateProcess.

• Флаг PROCESS_QUERY_INFORMATION разрешает использовать

дескриптор функциями GetExitCodeProcess и GetPriorityClass для получения

информации о процессе.

И наконец, выполняющийся процесс может определить имя своего

загрузочного файла с помощью функции GetModuleFileName, используя в

качестве параметра hModule указатель NULL. Вызов этой функции из

динамической библиотеки возвратит имя файла DLL, а не файла .ЕХЕ,

используемого библиотекой.

Копирование дескрипторов

Родительскому и дочернему процессам может потребоваться различный

доступ к объекту, который определяется дескриптором, унаследованным

дочерним процессом. Также процессу может потребоваться его настоящий

наследуемый дескриптор вместо псевдодескриптора, создаваемого функцией

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

необходимыми правами доступа и видом наследования. Ниже представлена

функция для копирования дескрипторов.

BOOL DuplicateHandle(

HANDLE hSourceProcessHandle, // дескриптор процесса источника

HANDLE hSourceHandle, // исходный дескриптор

HANDLE hTargetProcessHandle, // дескриптор процесса приемника

LPHANDLE lpTargetHandle, // дубликат исходного дескриптора

DWORD dwDesiredAccess, // флаги доступа к объекту

BOOL bInheritHandle, // наследование дескриптора

DWORD dwOptions // дополнительные необязательные флаги

);

Если функция DuplicateHandle завершается успешно, то она возвращает

ненулевое значение. В противном случае эта функция возвращает значение

FALSE.

Создание объекта ядра

Когда процесс инициализируется в первый paз, таблица описателей еще пуста. Но стоит одному из его потоков вызвать функцию, создающую объект ядра (например, CreateFtleMapping), как ядро выделяет для этого объекта блок памяти и инициализирует его, далее ядро просматривает таблицу описателей, принадлежащую данному процессу, и отыскивает свободную запись. Поскольку таблица еще пуста, ядро обнаруживает структуру с индексом 1 и инициализирует ее. Указатель устанавливается на внутренний адрес структуры данных объекта, маска доступа — на доступ без ограничений и, наконец, определяется последний компонент — флаги (О флагах мы поговорим позжс, в разделе о наследовании )

Вот некоторые функции, создающие объекты ядра (список ни в коей мере на полноту не претендует)

HANDLE CreateThread(
PSECURITY_ATTRIBUTES psa,
DWORD dwStackSize,
PTHREAD_START_ROUTINE pfnStartAddr,
PVOID pvParam,
DWORD dwCreationFlags,
PDWORD pdwfhreadId);

HANDEE CreateFile(
PCTSTR pszFileName,
DWORD dwDesiredAccebS,
DWORD dwShareMode,
PSECURITY_ATTRIBUTES psa,
DWORD dwCreationDistribution,
DWORD dwFlagsAndAttnbutes,
HANDEE hTemplateFile);

HANDLE CreateFileMapping(
HANDLE hFile,
PSECURITY_ATTRIBUTES psa,
DWORD flProtect,
DWORD dwMdximumSizcHigh,
DWORD dwMaximumSizeLow,
PCTSTR pszName);

HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTES psa,

LONG lInitialCount,
LONG lMaximumCount,
PCTSTR pszName);

Все функции, создающие объекты ядра, возвращают описатели, которые привязаны к конкретному процессу и могут быть использованы в любом потоке данного процесса Значение описателя представляет собой индекс в таблице описателей, принадлежащей процессу, и таким образом идентифицирует место, где хранится информация, связанная с объектом ядра. Вот поэтому при отладке своего приложения и просмотре фактического значения описателя объекта ядра Вы и видите такие малые величины: 1, 2 и т. д. Но помните, что физическое содержимое описателей не задокументировано и может быть изменено. Кстати, в Windows 2000 это значение определяет, по сути, не индекс, а скорее байтовое смещение нужной записи от начала таблицы описателей.

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

Если Вы передаете неверный индекс (описатель), функция завершается с ошибкой и GetLastError возвращает 6 (ERROR_INVALID_HANDLE). Это связано с тем, что на самом деле описатели представляют собой индексы в таблице, их значения привязаны к конкретному процессу и недейовительны в других процессах.

Если вызов функции, создающей объект ядра, оказывается неудачен, то обычно возвращается 0 (NULL). Такая ситуация возможна только при острой нехватке памяти или при наличии проблем с защитой. К сожалению, отдельные функции возвращают в таких случаях пе 0, а -1 (INVALID_HANDLE_VALUE) Например, если CreateFile не сможет открыть указанный файл, она вернет именно INVALID_HANDLE_VALUE. Будьте очень осторожны при проверке значения, возвращаемого функцией, которая создает объект ядра. Так, для CreateMutex проверка на INVALID_HANDlE_VALUE бессмысленна:

HANDLE hMutex = CreateMutex(...);
if (hMutex == lNVALID_HANDLE_VALUE) {
// этот код никогда не будет выполнен, так как
// при ошибке CreateMutex возвращает NLlLL
}

Точно так же бессмыслен и следующий код:

HANDIE hFile = CreateFile(.. );
if (hFile — NULL} {
// и этот код никогда не будет выполнен, так как
// при ошибке CreateFile возвращает lNVALID_HANDLE_VALUE (-1)
}

Закрытие объекта ядра

Независимо от того, как именно Вы создали объект ядра, по окончании работы с ним его нужно закрьпь вызовом CloseHandle

BOOL CloseHandle(HANDLE hobj);

Эта функция сначала проверяет таблицу описателей, принадлежащую вызывающему процессу, чтобы убедиться, идентифицирует ли переданный ей индекс (описа

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

Если же описатель невереи, происходит одно из двух. В нормальном режиме выполнения процесса CloseHandle возвращает FALSE, a GetLastError — код ERROR_INVALID_HANDLE. Но при выполнении процесса в режиме отладки система просто уведомляет отладчик об ошибке.

Перед самым возвратом управления CloseHandle удаляет соответствующую запись из таблицы описателей: данный описатель тспсрь недействителен в Вашем процессе и использовать его нельзя. При этом запись удаляется независимо от того, разрушен объект ядра или нет! После вызова CloseHandle Вы больше не получите доступ к это-
му объекту ядра; но, если его счетчик не обнулен, объект остается в памяти Тут все нормально, это означает лишь то, что объект используется другим процессом (или процессами). Когда и остальные процессы завершат свою работу с этим объектом (тоже вызвав CloseHandle), он будет разрушен.

А вдруг Вы забыли вызвать CloseHandle — будет ли утечка памяти? И да, и нет. Утечка ресурсов (тех же объектов ядра) вполне вероятна, пока процесс еще исполняется. Однако по завершении процесса операционная система гарантированно освобождает все ресурсы, принадлежавшие этому процессу, и в случае объектов ядра действует так: в момент завершения процесса просматривает его таблицу описателей и закрывает любые открытые описатели.



2016-01-02 835 Обсуждений (0)
Учет пользователей объектов ядра 0.00 из 5.00 0 оценок









Обсуждение в статье: Учет пользователей объектов ядра

Обсуждений еще не было, будьте первым... ↓↓↓

Отправить сообщение

Популярное:
Личность ребенка как объект и субъект в образовательной технологии: В настоящее время в России идет становление новой системы образования, ориентированного на вхождение...
Как вы ведете себя при стрессе?: Вы можете самостоятельно управлять стрессом! Каждый из нас имеет право и возможность уменьшить его воздействие на нас...



©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (835)

Почему 1285321 студент выбрали МегаОбучалку...

Система поиска информации

Мобильная версия сайта

Удобная навигация

Нет шокирующей рекламы



(0.007 сек.)