6장. 커널 오브젝트와 오브젝트 핸들
1. 커널 오브젝트에 대한 이해
커널 오브젝트
- 커널에서 관리하는 중요한 정보(리소스 정보)를 담아둔 데이터 블록을 가리켜 커널 오브젝트라 한다.
- 리소스: 운영체제에 의해서 생성 및 소멸되는 것
커널 오브젝트의 이해
CreateProcess 함수 호출을 통해 프로세스 생성
- 이는 CreateProcess 함수 호출을 통해 프로세스 생성을 요구한 것이고, Windows 운영체제가 우리의 요구에 맞게 프로세스를 생성해준 것
- 따라서, 프로세스를 생성하는 실질적인 주체는 운영체제이다.
- 이렇듯, 프로세스 관리(프로세스 생성 및 소멸, 프로세스 상태 변화)도 운영체제의 몫이다.
프로세스 관리 구조체
-
동시에 여러 개의 프로세스를 관리하기 위해, 운영체제 입장에서 고정적으로 저장하고 갱신해야 할 정보들이 존재한다.
-
예를 들어, 프로세스 상태 정보(Running, Blocked, Ready 상태)와 우선순위 정보는 운영체제 내부에 저장되어야 한다.
-
그리고 프로세스 스케줄러가 프로세스 상태 정보와 프로세스 우선순위 정보가 변경될 때 마다 갱신되어야 이를 바탕으로 프로세스를 관리할 수 있음
-
운영체제가 프로세스를 관리하기 위해서는 프로세스에 관련된 몇몇 정보를 저장할 수 있어야 하고, 참조 및 변경도 가능해야 한다.
-
이를 위해, 고안된 것이 프로세스 관리 구조체이다.
커널 오브젝트의 정체
- 프로세스가 생성될 때 마다 '프로세스 관리 구조체' 변수가 하나씩 생성되고, 새롭게 생성된 프로세스 정보들로 초기화되는데, 이것이 커널 오브젝트이다.
그 이외의 커널 오브젝트들
- 프로세스가 생성될 때에만 커널 오브젝트가 생성되는 것은 아니다.
- 프로세스 내에서 프로그램 흐름을 구성하는 쓰레드를 생성할 때 에도, IPC(Inter Process Communication)를 위해 사용되는 파이프나 메일슬롯을 생성할 때 에도 커널 오브젝트를 생성해서 필요한 정보를 채워 운영체제가 이들을 관리할 수 있도록 해야 한다.
- 뿐만 아니라, Windows에서는 파일을 생성할 때 파일 조차도 커널에 의한 관리 대상이므로 커널 오브젝트가 생성된다.
Windows에서 만드는 모든 종류의 커널 오브젝트들은 동일한 구조체로부터 생성될까?
- 대상에 따라서 관리되어야 할 사항이 다르기 때문에 커널 오브젝트 형태(커널 오브젝트를 구성하는 멤버)도 다르다. 그렇기 때문에 커널 오브젝트 종류에 따라 서로 다른 구조체를 기반으로 생성된다.
요약
Windows 운영체제는 프로세스, 쓰레드 혹은 파일과 같은 리소스(Resource)들을 원활하게 관리하기 위해서 필요한 정보를 저장해야 한다. 이 때 데이터를 저장하는 메모리 블록을 가리켜 커널 오브젝트라고 한다.
오브젝트 핸들(Handle)을 이용한 커널 오브젝트의 조작
- 프로그래머가 커널 오브젝트를 직접 조작할 수 없지만, 프로세스 우선순위 변경과 같은 Windows에서 관리하는 리소스 특성을 변경시키기 위해 해당 리소스의 커널 오브젝트를 마이크로소프트에서 제공하는 시스템 함수를 이용하여 간접적으로 조작할 수 있다.
프로세스의 우선순위(Priority) 변경
BOOL SetPriorityClass (
HANDLE hProcess,
DWORD dwPriorityClass
);
- hProcess: 우선순위를 변경할 프로세스의 핸들(Handle) 전달
- dwPriorityClass: 새롭게 적용할 우선순위 정보 전달
"SetPriorityClass 함수의 첫 번째 인자로 전달된 hProcess가 가리키는 프로세스의 우선순위를 두 번째 인자로 전달된 dwPriorityClass로 변경"
커널 오브젝트에 할당되는 숫자! 핸들(Handle)
- 특정 프로세스의 우선순위를 높이기 위해서 프로세스 커널 오브젝트에 존재하는 우선순위 정보를 변경해 줘야한다.
- Windows는 커널 오브젝트를 생성할 때 마다 특정 커널 오브젝트를 가리키는 핸들이라는 정수값을 하나씩 부여하기 때문에 SetPriorityClass 함수를 통해서 커널 오브젝트를 지시할 수 있다.
- SetPriorityClass 함수의 첫 번째 인자를 통해 우선 순위를 변경하고자 하는 프로세스의 커널 오브젝트를 가르키는 핸들을 전달한다.
2. 커널 오브젝트와 핸들의 종속 관계
커널 오브젝트의 종속 관계
"커널 오브젝트는 Windows 운영체제에 종속적이다."
커널 오브젝트가 프로세스가 아닌 Windows 운영체제(커널)에 종속적이라고 표현할 수 있는 이유
도서: 커널 오브젝트
도서 대여점에 등록된 고객: 프로세스
도서 대여점: 운영체제
- 도서는 고객에 종속적인 것이 아닌, 도서 대여점에 의해서 소유되고 관리되므로 도서 대여점에 종속적인 관계가 있으며 도서의 폐기는 도서 대여점에 의해서 결정된다. 즉, 커널 오브젝트도 프로세스에 종속적인 것이 아닌, 운영체제(커널)에 종속적인 관계로 커널 오브젝트의 소멸 시점은 운영체제(커널)에 의해서 결정된다.
- 도서는 고객에게 소유되거나 관리되지 않고, 도서 대여점에 등록된 고객에게 대여만 가능할 뿐이다. 이처럼 도서는 고객에 종속적이지 않고 여러 고객에 의해서 대여가 가능하다. 즉, 커널 오브젝트는 프로세스에 종속적인 것이 아니라 운영체제에 종속적인 관계로 여러 프로세스에 의해서 접근이 가능하다.
핸들의 종속 관계
- 핸들은 커널 오브젝트와 반대로 운영체제에 종속적이지 않고 프로세스에 종속적이다.
3. 커널 오브젝트와 Usage Count
"커널 오브젝트는 프로세스에 종속적인 것이 아니라, 운영체제에 종속적인 관계로 커널 오브젝트 소멸 시기는 운영체제에 의해서 결졍된다."
커널 오브젝트를 생성한 주체는 누구일까?
- CreateProcess 함수 호출은 단지 프로세스 생성에 대한 요청이며, 이 요청 과정에서 운영체제가 관리의 용이성을 위해 커널 오브젝트를 생성한 것이다.
- 즉, 커널 오브젝트의 생성 주체는 운영체제이다.
CloseHandle 함수에 대한 정확한 이해
- 프로세스가 생성되면, 그 프로세스를 위한 커널 오브젝트가 생성된다.
- 하지만, 프로세스가 소멸된다고 해서 커널 오브젝트가 소멸된다고 말할 수 없다.
- 이는 운영체제가 커널 오브젝트의 소멸 시기를 결정하기 때문이다.
BOOL CloseHandle (
HANDLE hObject
);
- CloseHandle 함수는 이름처럼 핸들을 닫는 기능을 갖는다.
가정: A 프로세스가 생성되고 A 프로세스 실행 과정에서 B 프로세스를 생성한다. 그리고 나서 B 프로세스의 핸들을 이용해서 CloseHandle 함수를 호출한다.
- 만약 이 상황에서 호출된 CloseHandle 함수에 의해 B 프로세스가 종료된다면, CloseHandle 함수는 프로세스 종료 및 커널 오브젝트 반환을 통해서 해당 커널 오브젝트가 소멸되었다고 할 수 있을까?
- 이에 대한 답변으로는 CloseHandle 함수 호출에 의해 B 프로세스가 소멸되지 않았다고 말할 수 있다.
CloseHandle 함수와 프로세스 종료 코드
운영체제는 커널 오브젝트 소멸시점을 어떻게 결정지을 수 있을까?
- 일단 프로세스가 종료되어야 한다. 그러나 프로세스 종료 시 해당 커널 오브젝트를 소멸시키면 문제가 발생한다.
- 왜나하면 해당 프로세스가 정상적으로 종료되어, 커널 오브젝트를 참조하는 대상(프로세스)이 하나도 없을 때 커널 오브젝트를 소멸시키는 것이 가장 이상적이기 때문이다.
- 이를 위해 프로세스가 종료됨을 확인할 수 있는 종료 코드를 알아야 한다.
커널 오브젝트와 Usage Count
- 앞서 들었던 예시를 다시 사용하여 부모 프로세스를 A 프로세스 그리고 자식 프로세스를 B 프로세스라고 하자.
- 그렇다면 자식 프로세스가 종료되었을 때, 자식 프로세스에 해당하는 커널 오브젝트를 부모 프로세스가 종료시켜야 한다.
- 이 때, 자식 프로세스가 종료됨을 확인하기 위한 방법이 필요하다.
자식 프로세스의 종료 코드는 자식 프로세스의 커널 오브젝트에 저장된다
- 따라서, 자식 프로세스가 종료될 때 커널 오브젝트도 동시에 소멸된다면 부모 프로세스는 자식 프로세스의 커널 오브젝트에 저장된 종료 코드를 알 수 없게된다.
- 이렇기 때문에 프로세스가 종료되었다고 해서 커널 오브젝트가지 동시에 소멸시킬 수 없다.
커널 오브젝트 소멸시기가 프로세스 종료시기와 일치하면 안된다.
그렇다면 언제 커널 오브젝트를 소멸시키는 것이 좋을까?
- 해당 커널 오브젝트를 참조하는 대상이 하나도 없을 때 소멸시키는 것이 가장 이상적이고, 이것이 Windows가 커널 오브젝트를 소멸시키기를 결정하는 방식이다.
- 즉, 커널 오브젝트를 참조하는 프로세스가 하나라도 있다면 커널 오브젝트는 소멸하지 않는다.
Windows는 이러한 정책을 기반으로 커널 오브젝트 소멸 시기를 결정하기 위해서 Usage Count(참조 횟수)라는 것을 관리한다.
- Usage Count가 0이 되는 순간 해당 커널 오브젝트는 소멸된다.
- 프로세스는 생성과 동시에 커널 오브젝트의 Usage Count가 1이 된다.
- 생성과 동시에 Usage Count가 0으로 초기화된다면, 커널 오브젝트 소멸 원칙에 의해 생성과 동시에 소멸된다.
- 초기화된 이후, 커널 오브젝트에 접근 가능한 대상이 늘어날 때마다 Usage Count가 하나씩 증가한다. 이는 커널 오브젝트에 접근 가능한 핸들 개수의 증가를 의미한다.
- 부모 프로세스는 자식 프로세스를 생성하는 과정에서 자식 프로세스의 핸들을 얻기 때문에 자식 프로세스가 생성되면 Usage Count는 2가 된다.
Usage Count와 CloseHandle
Usage Count가 0으로 감소하여 커널 오브젝트가 완전히 소멸되는 시점을 알아보자
- 자식 프로세스가 종료되었다는 의미는 자식 프로세스의 커널 오브젝트에 접근하는 대상이 하나 줄었다는 의미이고, 이는 Usage Count가 1이 되어었다는 의미이다. 이처럼 자식 프로세스가 종료되었더라도, 자식 프로세스가 종료되었다는 종료코드 정보를 담고있는 커널 오브젝트의 Usage Count가 1이기 때문에 소멸되지 않는다.
- 자식 프로세스가 종료되는 시점에서 CloseHandle 함수를 호출한다고 가정하자. CloseHandle 함수에 전달되는 인자는 자식 프로세스의 핸들이므로, 자식 프로세서의 커널 오브젝트에 더 이상 접근하지 않겠다는 의미를 지니고 있다. 따라서 이 때 Usage Count가 하나 더 감소한다.
- 결국 커널 오브젝트의 Usage Count는 0이되고, 커널 오브젝트 소멸 원칙에 의해서 소멸하게 된다.
CloseHandle 함수는 더 이상 접근하지 않고자 하는 프로세스의 핸들을 반환하면서 커널 오브젝트의 Usage Count를 하나 감소시키는 기능을 지닌다.
Reference