윈도우즈 시스템 프로그래밍을 공부하면서 정리한 글입니다.
6장. 커널 오브젝트와 오브젝트 핸들
I. 커널 오브젝트에 대한 이해
- 커널 : 컴퓨터를 운영하는데 있어서 중심이 되는 운영체제의 핵심 부분
-> 일반적으로 커널과 운영체제를 같은 의미로 사용
- 커널 오브젝트 : 커널에서 관리하는 중요한 정보들을 담아둔 데이터 블록
1. 커널 오브젝트의 이해
- 프로세스의 생성과 소멸, 상태 벼화, 관리는 모두 운영체제 몫
- 여러개의 프로세스르 관리하면 고정적으로 저장하고 갱신할 정보가 존재
ex) 프로세스 상태 정보 ( Running, Blocked, Ready 상태 ), 우선순위 정보
=> 운영체제 내부에 저장되어야 할 정보, 변경될 때 마다 갱신되어야 함
-> 프로세스 스케쥴러가 이를 바탕으로 프로세스를 관리
- 프로세스에 관련된 정보를 저장, 참조 및 변경할 수 있는 구조체 존재
(편의상 '프로세스 관리 구조체'라 함)
- 프로세스가 생성된 후 정보를 초기화 한 것이 커널 오브젝트
- 프로세스 관리 구조체는 어떻게 구성되어 있는지 알 수 없음 (마이크로소프트가 공개하지 않음)
=> 프로세스의 커널 오브젝트는 프로그래머가 직접 생성하거나 조작하는 것을 막음
- Windows 커널에 의해 관리되는 리소스 수 만큼 커널 오브젝트도 생성됨
CreateProcess 함수 호출이 커널 오브젝트의 생성 원인이나 단지 프로세스의 생성을 요청할 뿐
프로세스 생성의 주체는 운영체제이다. (함수가 아님)
- 프로세스 생성시, 그 프로세스르 위한 커널 오브젝트가 생성됨
- but 프로세스가 소멸한다고 해서 커널 오브젝트가 소멸하진 않음
=> 소멸할 수도 있으나 하지 않을 수도 있음
- BOOL CloseHandle (
Handle hObject // 핸들을 닫음(반환) -> 핸들의 소멸, 리소스 해제를 의미하지 않음
);
- 핸들값은 커널 오브젝트에 매핑되지 않음 -> 각각의 핸들 테이블에서 핸들 값을 사용
=> ∴ 핸들 값, 핸들 테이블은 프로세스에 종속적
- 자식프로세스가 사라지면 프로세스에 종속적인 핸들 테이블이 사라지나
부모 프로세스에서 자식 프로세스 커널 오브젝트를 보고 있으므로 (핸들 테이블에서 사용중)
커널 오브젝트는 사라지지 않고 단지 Usage Count를 2에서 1로 감소시킴
=> UC(Usage Count)가 존재하는 이유
- 운영체제 영역에서 커널 오브젝트가 있음 = 커널 오브젝트의 소멸은 운영체제게 UC를 통해 정함
- UC가 0이 되면 커널 오브젝트는 소멸 ( but 파일은 물리적으로 남아있음)
Q1. 프로세스 생성시 자기 자신의 커널 오브젝트를 핸들 테이블에서 참조하는가?
- 프로세스 생성시 자기 자신의 커널 오브젝트에 대한 핸들정보는 핸들 테이블에 저장하지 않음
but GetCurrentProcess는 상수(-1)을 리턴
- 함수들은 -1이 리턴 되면 현재 프로세스를 지칭 한다고 인식함 (windows의 약속)
Q2. 자식프로세스가 종료된 후 부모 프로세스가 자식 프로세스의 커널 오브젝트를 참조한다고 해서
커널 오브젝트를 남겨둘 이유가 있는가?
- 부모 프로세스는 자식 프로세스가 정상 종료 햇는가가 궁금함
- 자식 프로세스가 소멸되자 마자 자식 프로세스의 커널 오브젝트가 소멸되면
부모 프로세스는 자식 프로세스의 정상 종료 여부를 알지 못함
=> ∴ UC를 통해 운영체제가 커널 오브젝트를 관리!
- STARTUPINFO si = {0, }; // 프로세스 생성시 초기 정보를 전달하는 목적
si.cb= sizeof(si);
- PROCESS_INFORMATION pi; /// 생성된 프로세스의 정보를 얻기 위한 구조체 (핸들값 얻을 수있음)
- 자식 프로세스가 종료되더라도 부모 프로세스의 참조에 의해 자식 프로세스의 커널 오브젝트는 남음
-> but 종료코드를 얻고 더이상 커널 오브젝트를 참조할 필요가 없다면 UC를 0으로 만들어 운영체제가 소멸시키도록 해야함
( 자원 낭비를 막기위해 )
=> CloseHandle (pi.hProcess); // 함수를 이용해 UC를 하나 줄여 메모리 낭비 방지
- 프로세스 관리 구조체는 어떻게 구성되어 있는지 알 수 없음 (마이크로소프트가 공개하지 않음)
=> 프로세스의 커널 오브젝트는 프로그래머가 직접 생성하거나 조작하는 것을 막음
2. 그 이외의 커널 오브젝트
- 프로세스 내에 쓰레드를 생성할 때, IPC를 위해 사용하는 파이프나 메일 슬롯을 생성할 때도
커널 오브젝트를 생성해야 함
- 커널 오브젝트 종류에 따라 다른 구조체를 생성
ex) 파일 커널 오브젝트 -> 파일 속성 정보 (Read모드, Read / Write모드 ... )
프로세스 커널 오브젝트 -> 프로세스 우선 순위 정보 (스케쥴링을 위해)
=> ∴ Windows 운영체제는 프로세스, 쓰레드와 파일 같은 Resource 들을 원활히 관리하기 위해
데이터를 저장하는 메모리 블록이 존재 => 커널 오브젝트
- 데이트 블록 : 커널 오브젝트 | 프로세스나 파일 : Resource
- Windows 커널에 의해 관리되는 리소스 수 만큼 커널 오브젝트도 생성됨
II. 오브젝트 핸들(Handle)을 이용한 커널 오브젝트의 조작
- 프로그래머는 직접 커널 오브젝트를 조작할 수 없음
- 리소스의 특성을 변경하기 위해선 (프로세스 우선 순위 변경 같은)
해당 리소스 커널 오브젝트를 조작해야함
-> 마이크로소프트에서 제공하는 시스템 함수를 이용 (안정적인 방식)
1. 프로세스 우선순위 (Priority) 변경
ex)
BOOL SetPriorityClass (
HANDLE hProcess; // 우선 순위를 변경할 프로세스의 핸들
DWORD dwPriorityClass; // 새롭게 적용할 우선 순위
);
- 핸들 (Handle) : 커널 오브젝트에 할당되는 숫자 (정수형)
2. 커널 오브젝트에 할당되는 숫자 = 핸들 (Handle)
- Windows는 커널 오브젝트를 생성할 때 마다 핸들을 하나씩 부여
3. 핸들 정보
- 핸들 정보를 얻는 방법은 커널 오브젝트 종류에 따라서 다양함 ( 프로세스, 파일, 쓰레드 ...)
- GetCurrentProces 함수 -> 현재 실행되고 있는 프로세스의 핸들을 얻을 떄 사용
=> 항상 같은 값을 리턴(-1)
- '-1'은 자기 자신을 의미
- 함수가 호출되어 실행되는 중에 (함수는 여러개의 명령어로 구성) CPU 할당시간을
다른 프로세스에 넘겨줄 수 있음
=> 우선순위를 넘기는 기준은 CPU 관점에서 명령어 단위가 기준
III. 커널 오브젝트와 핸들의 종속관계
1. 커널 오브젝트의 종속 관계
- 커널 오브젝트는 Windows 운영체제에 종속적
① 커널 오브젝트에 종속적인 것이 아니라, 운영체제에 종속적인 관계로
커널 오브젝트의 소멸 시점은 운영체제에 의해 결정됨
② 커널 오브젝트는 여러 프로세스에 의해 접근이 가능 (물론 함수 호출을 통한 간접 호출)
2. 핸들의 종속 관계
- 핸들 (핸들 테이블) 은 운영체제에 종속적이지 않고 프로세스에 종속적
ex) 프로세스의 우선 순위를 높이기 위해서는 핸들을 이용해 커널 오브젝트에 접근.
- PROCESS_INFORMATION 구조체
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess; // 프로세스 핸들
HANDLE hThread; // 쓰레드 핸들
DWORD dwProcessID; // 프로세스의 ID
DWORD dwThreadID; // 쓰레드의 ID
} PROCESS_INFORMATION;
ex) 프로세스의 우선 순위를 높이기 위해서는 핸들을 이용해 커널 오브젝트에 접근.
- PROCESS_INFORMATION 구조체
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess; // 프로세스 핸들
HANDLE hThread; // 쓰레드 핸들
DWORD dwProcessID; // 프로세스의 ID
DWORD dwThreadID; // 쓰레드의 ID
} PROCESS_INFORMATION;
3. 프로세스 핸들과 ID
- 운영체제는 프로세스 생성시 프로세스들을 구분짓기 위해 ID(식별자)를 할당
- 프로세스 핸들 : 프로세스의 커널 오브젝트를 가리키기(구분짓기) 위함
- 프로세스 ID : 커널 오브젝트가 아니라 프로세스 자체를 구분짓기 위함
- CreateProcess 함수를 통해 프로세스를 생성하면 쓰레드라는 시스템 리소스도 생성됨
IV. 커널 오브젝트와 Usage Unit
1. CloseHandle 함수에대한 정확한 이해
CreateProcess 함수 호출이 커널 오브젝트의 생성 원인이나 단지 프로세스의 생성을 요청할 뿐
프로세스 생성의 주체는 운영체제이다. (함수가 아님)
- 프로세스 생성시, 그 프로세스르 위한 커널 오브젝트가 생성됨
- but 프로세스가 소멸한다고 해서 커널 오브젝트가 소멸하진 않음
=> 소멸할 수도 있으나 하지 않을 수도 있음
- BOOL CloseHandle (
Handle hObject // 핸들을 닫음(반환) -> 핸들의 소멸, 리소스 해제를 의미하지 않음
);
2. 커널 오브젝트와 Usage Count
- 자식 프로세스의 종료코드는 자식 프로세스 커널 오브젝트에 저장됨
- if 자식 프로세스가 종료될 때 커널 오브젝트도 소멸되면 종료코드는 사라짐
=> ∴ 프로세스가 종료되어도 커널 오브젝트는 동시에 소멸하지 않음
- 해당 커널 오브젝트를 참조하는 대상이 없을 때 소멸하는 것이 이상적
=> windows가 커널 오브젝트를 소멸 시키는 방법
- 프로세스의 생성과 동시에 커널 오브젝트의 Usage Count=1
- 프로세스에 접근 가능한 핸들 수가 늘어날때 마다 Usage Count 증가
- 자식프로세스의 Usage Count=2 (부모 프로세스 참조 + 자기자신 참조)
=> 부모프로세스가 CreateProcess 함수 호출과정에서 PROCESS_INFORMATION
구조체를 통해 자식 프로세스의 핸들을 얻기 때문
- 핸들값은 커널 오브젝트에 매핑되지 않음 -> 각각의 핸들 테이블에서 핸들 값을 사용
=> ∴ 핸들 값, 핸들 테이블은 프로세스에 종속적
- 자식프로세스가 사라지면 프로세스에 종속적인 핸들 테이블이 사라지나
부모 프로세스에서 자식 프로세스 커널 오브젝트를 보고 있으므로 (핸들 테이블에서 사용중)
커널 오브젝트는 사라지지 않고 단지 Usage Count를 2에서 1로 감소시킴
=> UC(Usage Count)가 존재하는 이유
- 운영체제 영역에서 커널 오브젝트가 있음 = 커널 오브젝트의 소멸은 운영체제게 UC를 통해 정함
- UC가 0이 되면 커널 오브젝트는 소멸 ( but 파일은 물리적으로 남아있음)
Q1. 프로세스 생성시 자기 자신의 커널 오브젝트를 핸들 테이블에서 참조하는가?
- 프로세스 생성시 자기 자신의 커널 오브젝트에 대한 핸들정보는 핸들 테이블에 저장하지 않음
but GetCurrentProcess는 상수(-1)을 리턴
- 함수들은 -1이 리턴 되면 현재 프로세스를 지칭 한다고 인식함 (windows의 약속)
Q2. 자식프로세스가 종료된 후 부모 프로세스가 자식 프로세스의 커널 오브젝트를 참조한다고 해서
커널 오브젝트를 남겨둘 이유가 있는가?
- 부모 프로세스는 자식 프로세스가 정상 종료 햇는가가 궁금함
- 자식 프로세스가 소멸되자 마자 자식 프로세스의 커널 오브젝트가 소멸되면
부모 프로세스는 자식 프로세스의 정상 종료 여부를 알지 못함
=> ∴ UC를 통해 운영체제가 커널 오브젝트를 관리!
- STARTUPINFO si = {0, }; // 프로세스 생성시 초기 정보를 전달하는 목적
si.cb= sizeof(si);
- PROCESS_INFORMATION pi; /// 생성된 프로세스의 정보를 얻기 위한 구조체 (핸들값 얻을 수있음)
- 자식 프로세스가 종료되더라도 부모 프로세스의 참조에 의해 자식 프로세스의 커널 오브젝트는 남음
-> but 종료코드를 얻고 더이상 커널 오브젝트를 참조할 필요가 없다면 UC를 0으로 만들어 운영체제가 소멸시키도록 해야함
( 자원 낭비를 막기위해 )
=> CloseHandle (pi.hProcess); // 함수를 이용해 UC를 하나 줄여 메모리 낭비 방지
참고 : 뇌를 자극하는 윈도우즈 시스템 프로그래밍. 윤성우 저
좋은 글 감사합니다~
답글삭제