2012년 8월 27일 월요일

윈도우즈 시스템 프로그래밍 [6] - 커널 오브젝트와 오브젝트 핸들




윈도우즈 시스템 프로그래밍을 공부하면서 정리한 글입니다.



6장. 커널 오브젝트와 오브젝트 핸들



I. 커널 오브젝트에 대한 이해


- 커널 : 컴퓨터를 운영하는데 있어서 중심이 되는 운영체제의 핵심 부분
   -> 일반적으로 커널과 운영체제를 같은 의미로 사용

- 커널 오브젝트 : 커널에서 관리하는 중요한 정보들을 담아둔 데이터 블록


1. 커널 오브젝트의 이해


- 프로세스의 생성과 소멸, 상태 벼화, 관리는 모두 운영체제 몫
- 여러개의 프로세스르 관리하면 고정적으로 저장하고 갱신할 정보가 존재
ex) 프로세스 상태 정보 ( Running, Blocked, Ready 상태 ), 우선순위 정보
   => 운영체제 내부에 저장되어야 할 정보, 변경될 때 마다 갱신되어야 함
   -> 프로세스 스케쥴러가 이를 바탕으로 프로세스를 관리

- 프로세스에 관련된 정보를 저장, 참조 및 변경할 수 있는 구조체 존재 
  (편의상 '프로세스 관리 구조체'라 함)

- 프로세스가 생성된 후 정보를 초기화 한 것이 커널 오브젝트


- 프로세스 관리 구조체는 어떻게 구성되어 있는지 알 수 없음 (마이크로소프트가 공개하지 않음)
   => 프로세스의 커널 오브젝트는 프로그래머가 직접 생성하거나 조작하는 것을 막음



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;


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를 하나 줄여 메모리 낭비 방지





참고 : 뇌를 자극하는 윈도우즈 시스템 프로그래밍. 윤성우 저 



댓글 1개: