본문 바로가기

CS/운영체제

Process가 생성되면서 PCB(Process Control Block)이 어떻게 변화할까?

프로그램을 명령어나 아이콘을 클릭함으로써 프로세스로 만드는데, 우리는 이 프로세스를 실행 중인 상태 OS의 제어를 받고 있는 상태라고 불렀습니다. 그래서 이 프로세스가 실행되려면 CPU가 연산을 처리하고 있는 것이죠? 그럼 CPU는 어떤걸 참조해서 연산과정을 처리하는 걸까요? 프로세스가 생성되면서, PCB(Process Control Block)가 동시에 생성됩니다. 이 내부에 어떤 과정이 있긴 합니다. 하지만 여기선 어떻게 할당 되는지 저장되는지 초기화 되는지를 설명해보겠습니다.


PCB는 어떻게 할당되어 질까?


할당은 여러가지 방법들이 존재하는데, 그중에서 사전 할당(Pre Allocation)이 있습니다. 우리가 잘 아는 Pool 있죠, DB의 Connection Pool처럼 바로 Connection을 할당해 주는 방법입니다. Pool이라는 것은 미리 만들어 두는 것을 의미합니다.

예전에 메모리가 크지 않던 시절은 동적으로 필요한 만큼만 만들었지만, 현대에 와서는 메모리의 크기가 크기 때문에 미리 Process Pool을 만들어서 즉시 할당해주는 방법을 사용합니다. (Linux에서는 Slab Allocator를 사용해 PCB와 같은 고정 크기의 객체를 할당합니다.)

할당받은 PCB는 어디에 저장될까?


PCB는 커널 메모리 공간(Kernel Space)에 저장됩니다. 일반적으로 Process Table에서 관리됩니다. Process Table은 커널 내부에 존재하며 모든 PCB를 해시 테이블 또는 다른 자료구조에서 관리하고 있습니다. 

또한, 커널 메모리 공간은 일반 프로세스가 접근할 수 없는 보호된 영역으로, 운영체제가 프로세스를 안전하게 관리하기 위해 사용됩니다. 



PCB에는 어떤 애들이 저장될까?


1. Register 

(1) Program Counter

PCB의 중요한 구성요소입니다. 해당 프로세스가 다음에 실행될 명령어의 주소를 가리키고 있습니다. 그래서 해당 프로세스의 Code 영역을 가리키고 있는 것이죠. Code 영역 내의 특정 주소를 가리키고 있다고 생각하면 됩니다. Process가 실행되려면 기계어로 번역된 Code 영역을 가리키는 포인터 역할을 합니다.

Program Counter는 일반적으로 명령어 실행 후 자동으로 증가하며 다음 명령어를 가리키게됩니다. 분기나 점프와 같은 명령어를 만나면 PC는 코드 영역 내의 다른 주소로 변경됩니다. 함수가 호출되면 해당 함수의 시작 주소로 변경되며, 함수에서 반환할 때 PC는 호출 지점 다음 명령어의 주소로 복원됩니다.

(2) Stack Pointer

Stack Pointer는 무엇이냐면, 함수가 호출되면 Stack Frame이 생성이 됩니다. PC는 그 위치를 가리키고 있긴 하지만, 함수 내의 지역변수 매개변수가 필요하다면 Stack Frame을 가리키고 있는 Stack Pointer로 지역 변수와 매개변수를 파악합니다.

이 과정이 어떻게 이루어지는지 써내려가보겠습니다.

함수 호출 명령어가 실행될 때, 현재 Program Counter 값 + 다음 명령어 주소가 스택에 자동으로 저장될 것이고, 이 값은 함수 실행이 완료된 후 어디로 돌아가야 할지를 나타내는 반환주소가 될 것입니다.

Call 명령어로 함수가 호출되고, Call 명령어 위치에서 다음 명령어 실행 위치를 더한 값을 Stack Frame에 저장하게 됩니다. 그리고 PC는 Call 명령어로 실행된 함수의 시작 위치를 가리키게 됩니다. 그 함수가 전부 처리가 되면, 스택에 저장해 뒀던 명령어의 반환 위치로 다시 돌아가 시작합니다. 그래서 스택 영역에는 지역변수, 매개변수, 반환 주소가 저장이 되어 있는데 PC가 Code 영역의 Machine Language를 차례로 읽으면서 명령을 실행하는데 그때 변수나 매개변수를 참조해야한다면 Stack Pointer가 가리키는 Stack Frame의 지역변수나 매개변수 값을 찾습니다. 스택 프레임에 접근해서 베이스 포인터(BP)와 프레임 포인터(FP)를 사용해 스택 프레임 내의 변수에 접근할 수 있습니다.

Stack Frame은 메모리 할당된 위치가 차례로, 매개변수, 반환 주소, 이전 프레임의 포인터, 지역변수 이렇게 되어 있습니다. 명령어가 mov, eax, [ebp-4] 이런식으로 EBP 베이스 포인터에서 4바이트 아래에 있는 지역 변수 값을 EAX 레지스터로 이동합니다. add [ebp-8], 5 처럼 EBP에서 8 바이트 아래에 있는 지역 변수 더하게 되는 것처럼 이렇게 지역변수에 접근하는 동작을 처리할 수 있습니다.

  • EBP(Extended Base Pointer) : 스택 프레임의 기준점
  • ESP(Extended Stack Pointer) : 스택 현재 최 상단

- accumlate
- Index Register
- EAX etc..

2. Process State

  • New, Ready, Run, etc..

3. Scheduling Information

  • 단기 스케줄러가 Ready Queue에 존재하는 프로세스를 선택하니까  FSFC,SJ,Priority,Round Robin 이런 식으로 선택되어 있습니다.

4. Memory Management

  • 페이지 테이블 포인터 또는 내 메모리 주소

5. Account Info

  • CPU 사용시간, 경과된 실시간, 시간 제한, 계정 번호

6. I/O State Info

  • Process에 할당된 I/O Device 

이렇게 저장되어있습니다. 여기까지 Process가 생성되면서 PCB가 어떻게 할당되고 저장되고 무엇이 초기화되는지 설명을 해보았습니다.


애매하거나 추가 검증이 필요한 내용

  1. Process Pool 개념
    • 현대 운영체제에서 PCB가 Slab Allocator 또는 유사한 메모리 관리 기법을 통해 빠르게 할당되는 것은 사실입니다. 하지만 "Process Pool"이라는 용어는 명확히 정의된 개념은 아닙니다.
    • 프로세스 자체의 Pool을 운영한다는 점은 흔하지 않으며, PCB의 Slab 캐싱은 특정 커널 구현에 따라 다릅니다. 이를 명확히 하기 위해 추가 자료 확인이 필요합니다.
  2. PCB 생성 시점
    • 내용에서 PCB가 프로세스 생성과 동시에 "즉시" 생성된다고 언급했지만, 일부 커널에서는 프로세스 생성 요청 단계에서 기본 구조만 초기화하고, 구체적인 PCB 초기화는 나중에 이루어질 수도 있습니다.
    • 예를 들어, Linux에서는 fork() 호출 시 task_struct가 복사되고, 자식 프로세스의 PCB가 초기화됩니다. 다른 운영체제에서는 약간 다른 방식일 수 있습니다.
  3. Process Table의 자료구조
    • PCB가 Process Table에 저장된다고 했지만, 구체적으로 어떤 자료구조가 사용되는지는 운영체제마다 다릅니다.
      • Linux는 해시 테이블과 연결 리스트를 사용해 PCB를 관리합니다.
      • Windows는 EProcess 구조체를 커널 객체로 관리합니다.
    • 이 부분은 명확히 운영체제별로 구분해서 이해해야 합니다.

더 알아봐야 할 사항

  1. Slab Allocator와 PCB 관리의 실제 동작
    • Linux의 Slab Allocator가 어떻게 PCB와 같은 객체를 관리하는지, 특히 어떤 조건에서 동적 할당과 캐시를 사용해 최적화를 이루는지 구체적으로 확인이 필요합니다.
    • 공식 Linux 커널 문서 또는 Daniel Bovet의 Understanding the Linux Kernel에서 확인 가능.
  2. PCB와 프로세스 테이블 관리 방식
    • 각 운영체제의 프로세스 테이블이 사용하는 자료구조와 저장 방식에 대한 비교. 예를 들어:
      • Linux의 task_struct 관리 방식.
      • Windows의 EProcess와 KProcess 구조체 관계.
  3. Process Pool의 개념 유무
    • Process Pool이라는 개념이 실제로 운영체제 설계 이론에서 사용되는지 확인이 필요합니다. PCB 관리가 Slab Allocator로 이루어지는 것은 사실이나, "Pool"이라는 용어가 정식으로 사용되지는 않는 경우가 많습니다.

Summary

운영체제에서 프로세스가 실행되기 위해 PCB가 생성, 초기화, 저장되는 과정은 다음과 같습니다:

  1. 프로세스 생성:
    • 운영체제는 fork(), exec(), CreateProcess()와 같은 시스템 호출로 새로운 프로세스를 생성합니다.
    • PID(프로세스 ID)가 할당되고 프로세스 생성이 시작됩니다.
  2. PCB 할당:
    • PCB는 커널 메모리(Slab Allocator 또는 다른 메모리 관리 기법)에서 할당됩니다.
    • PCB는 프로세스의 상태, 메모리 관리 정보, 스케줄링 정보, 레지스터 상태 등을 저장하는 데이터 구조입니다.
  3. PCB 초기화:
    • PCB는 PID, 프로세스 상태(초기에는 READY), 스케줄링 정보, 메모리 주소 공간 정보 등이 초기화됩니다.
    • Program Counter는 실행할 명령어의 첫 주소를 가리키도록 설정됩니다.
  4. PCB 저장:
    • PCB는 프로세스 테이블(Process Table)에 저장됩니다. 운영체제는 해시 테이블, 연결 리스트, 또는 기타 자료구조를 사용해 PCB를 관리합니다.
    • 프로세스는 이후 스케줄링 큐(예: Ready Queue)에 등록되어 CPU를 할당받을 준비를 합니다.