본문 바로가기

C, C++/뇌를 자극하는 윈도우즈 시스템 프로그래밍

[뇌를 자극하는 윈도우즈 시스템 프로그래밍] 6장 - 커널 오브젝트와 오브젝트 핸들

개요

커널은 운영체제의 핵심을 구성하는 부분으로, OS와 커널은 엄밀히는 구분되지만 일반적으로 같은 의미로 사용되기도 한다.

 

커널 오브젝트는 커널이 관리하는 중요한 정보를 담고 있는 데이터 구조체로, 운영체제에서 다양한 시스템 리소스를 추상화하고 제어하기 위해 사용된다.

이러한 객체를 지칭할 때 운영체제 오브젝트라는 용어는 사용하지 않고, 커널 오브젝트라고 부른다.

 

예를 들어, 운영체제가 새로운 프로세스를 생성할 때에는 해당 프로세스를 관리하기 위해 프로세스 상태, 우선순위, 핸들 테이블 등의 정보를 커널 내부에 저장한다.

이때 이러한 정보를 포함하고 있는 구조체가 바로 커널 오브젝트이며, 이를 통해 운영체제는 프로세스를 효과적으로 제어하고 관리할 수 있다.

 

커널 오브젝트는 프로세스 생성 외에도, 스레드 생성, IPC를 위한 파이프와 메일슬롯 생성 등에도 생성될 수 있다.

커널 오브젝트는 같은 구조체로부터 생성되는 것이 아닌 커널 오브젝트의 종류에 따라 서로 다른 구조체를 기반으로 생성된다.

 

Windows 커널에 의해서 관리되는 리소스의 수 만큼 커널 오브젝트도 생성된다.


오브젝트 핸들을 이용한 커널 오브젝트 조작

프로그래머는 직접 커널 오브젝트를 조작할 수 없지만, 시스템 함수를 통해 간접적으로 조작할 수 있다.

 

SetPriorityClass 같은 제공되는 함수를 통해 커널 오브젝트를 조정한다.

 

핸들(Handle)

프로세스가 커널 오브젝트를 특정하기 위해 '핸들' 이라는 값을 사용한다. 

Windows는 커널 오브젝트 생성 시 핸들이라는 정수 값을 부여한다.

이 값을 알고 있다면 커널 오브젝트를 특정할 수 있게된다.

 

간단하게는 GetCurrentProcess()를 통해 현재 프로세스의 핸들을 알 수 있다.


커널 오브젝트와 핸들의 종속 관계

커널 오브젝트는 프로세스에 종속적인 것이 아닌, Windows 운영체제에 종속적이다.

커널 오브젝트의 생성, 소멸 시점은 운영체제에 의해 결정된다.

 

커널 오브젝트는 운영체제에 종속적이기 때문에, 커널 오브젝트는 여러 프로세스가 접근할 수 있다.

 

다만 커널 오브젝트의 핸들은 운영체제가 아닌 프로세스에 종속적이다.

 

PROCESS_INFORMATION 

https://learn.microsoft.com/ko-kr/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_information

 

PROCESS_INFORMATION(processthreadsapi.h) - Win32 apps

새로 만든 프로세스 및 기본 스레드에 대한 정보를 포함합니다. CreateProcess, CreateProcessAsUser, CreateProcessWithLogonW 또는 CreateProcessWithTokenW 함수와 함께 사용됩니다.

learn.microsoft.com

typedef struct _PROCESS_INFORMATION {
  HANDLE hProcess;
  HANDLE hThread;
  DWORD  dwProcessId;
  DWORD  dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;

 

CreateProcess가 실행되면 전달했던 Process Information 구조체에 생성하는 프로세스의 핸들, 스레드의 핸들, 프로세스의 ID, 스레드의 ID가 채워진다.

 


커널 오브젝트와 Usage Count

프로세스가 소멸된다고, 커널 오브젝트가 무조건 소멸되는 것은 아니다.

 

자식 프로세스의 종료코드는 자식 프로세스가 종료되면, 자식 프로세스의 커널 오브젝트에 저장된다.

그렇다면 부모 프로세스가 자식 프로세스가 어떻게 종료되었는지 알기 위해서는 자식 프로세스의 커널 오브젝트에 접근할 필요가 있다.

 

위와 같이 어떤 프로세스가 종료되더라도, 해당 프로세스의 커널 오브젝트에 접근할 필요가 있을 수 있다.

따라서 해당 커널 오브젝트를 참조하는 대상이 하나도 없는 경우에 Windows(OS)가 소멸시키는 방법을 사용한다.

 

내부적으로 해당 커널 오브젝트를 참조하는 핸들의 개수 Usage Count(참조 횟수)를 관리하고, Usage Count가 0이 될 때 비로소 해당 커널 오브젝트를 소멸하는 방식을 사용한다.

 

프로세스는 생성과 동시에 본인의 Usage Count는 1이 된다. 자식 프로세스는 부모 프로세스와 자식 프로세스가 모두 자식 프로세스의 커널 오브젝트를 참조하기 때문에, Usage Count가 2가 된다. 

 

CloseHandle 함수를 사용하면, 해당 커널 오브젝트에 대한 핸들을 반환하면서, UsageCount를 1 감소시킨다.

물론 프로세스가 종료되는 시점에도 프로세스가 가진 자원들을 반환하기 때문에 Usage Count가 감소된다.

https://learn.microsoft.com/ko-kr/windows/win32/api/handleapi/nf-handleapi-closehandle

 

CloseHandle 함수(handleapi.h) - Win32 apps

열린 개체 핸들을 닫습니다.

learn.microsoft.com

 

부모 프로세스가 자식 프로세스에게 관심이 없는 경우(연관이 없는 프로세스) 자식 프로세스 생성 과정에서 얻게 되는 핸들을 곧바로 반환해 자식 프로세스가 종료되었을 때 커널 오브젝트도 바로 삭제될 수 있도록 한다.