[Operating System] Process

2020. 1. 16. 01:06Operating System

1. Process

Process란?

  • 현재 running 중인 프로그램의 인스턴스로 프로그램 instruction들의 execution stream이다.
  • 각 프로세스는 독립적인 주소공간, 레지스터, open file table을 가진다.

 

CPU Virtualization

  • 마치 CPU를 독점적으로 사용하는 듯한 착시를 주는 것.

    • by time sharing: 코어가 1개밖에 없더라도 프로세스 간에 context switch가 빠르게 이루어지면서 마치 서로 다른 프로그램들이 동시에 실행되는 듯한 착각을 준다.

    • by space-sharing: 각 프로세스들이 메모리와 디스크 전체를 독점적으로 사용하는 듯한 착각을 준다.
  • 싱글 코어 CPU의 time-sharing 과정 (Direct execution인 경우)

    • 유저 프로세스가 직접적으로 HW의 동작을 실행가능
    • OS는 process를 생성한 뒤론 process에게 컨트롤을 완전히 넘겨줌
    • 유저 app이 문제를 발생시켰을 경우 대책이 없어서 사용하지 않는 방법
  • Limited Direct Execution (Restricted Operation)

    • 프로세스가 HW와 interation하기 위해서는 반드시 syscall을 통해서 OS의 도움을 받아야만 함
    • I/O, 메모리 할당, 프로세스 간의 interaction 등은 오직 OS에서만 다룰 수 있다.
    • 유저 모드커널 모드를 분리

 

System Call

  • System Call: file system 접근 / 프로세스의 생성과 제거 / process 간의 커뮤니케이션 / 메모리 할당 등을 처리

  • Syscall의 과정

    • 유저 프로세스에서 syscall 함수 호출을 한다.
    • Syscall은 interrupt의 한 종류이기 때문에 IDTR(Interrupt Descriptor Table Register)을 통해서 IDT에 접근하고, trap table index (0x80)을 통해서 syscall table의 주소를 얻는다.
    • Kernel에서는 현재 프로세스의 context, state 등을 save한다.
    • Syscall table index에 해당하는 서비스 루틴을 실행한다. (index가 2번이면 fork 함수)

fork() 를 호출 했을 때의 동작 과정

 

 

Process vs Thread

하나의 process 안에 여러 개의 쓰레드가 돌아갈 수 있다. 다른 프로세스는 독립적인 address space와 context를 갖지만, 쓰레드들끼리는 고유한 register context를 제외하고서는 같은 address space를 공유한다.

 

Dispatcher Mechanism

앞에서 여러 프로세스들이 context switch를 하면서 함께 실행이 되고, system call을 하면 interrupt가 걸리면서 커널 모드로 들어가게 되고, 커널을 통해 여러 privilleged 작업을 수행한다는 것을 살펴보았다. 그렇다면 특정 프로세스가 돌아가고 있을 때 어떻게 그 프로세스로부터 컨트롤을 가져올 것인가? 또 context switch를 할 때 백업 해두어야 하는 정보는 무엇인가?

 

Context switch가 어떻게 이루어져야 하는지에 관한 매커니즘이 dispatcher mechanism이다. Context switch가 발생했을 때 컨트롤을 가져 오는 방법은 두 가지로 분류할 수 있다.

 

  1. Cooperative Method
    • 프로세스가 주기적으로 yield와 같은 시스템 콜을 통해서 컨트롤을 포기하고 다른 태스크가 돌아가도록 함.
    • 프로세스가 컨트롤을 넘겨주지 않기위해서 악성적인 행위를 할 수도 있음.
  2. Non-cooperative Method
    • timer interrupt를 사용하여 timer 주기에 따라서 새롭게 스케줄링을 함.
    • 현재 프로세스 정지 => 현재 프로세스 state를 save => 인터럽트 핸들러 동작
    • 타이머 인터럽트가 발생하면 현재 프로세스의 state를 커널 스택에 저장하고 커널 모드로 들어가서 인터럽트 핸들러를 실행한다. 그 후엔 현재 프로세스의 state를 PCB(혹은 proc_struct)에 저장하고 새로운 프로세스의 PCB로부터 새로운 프로세스의 state를 복원한다.

 

구체적인 Context Switch 과정

  1. 이전 프로세스의 state, context를 커널 스택에 저장
  2. 커널 모드의 trap handler로 점프
  3. trap handler의 루틴 실행
  4. 이전 프로세스의 state, context를 PCB에 저장
  5. 이전 프로세스는 ready queue에 삽입
  6. 다음 프로세스의 PCB에 저장된 state, context를 레지스터로 restore
  7. 유저 모드로 전환하여 PC 값에 해당하는 instruction 수행

 

Context Switch 시에 무엇을 저장하고 복원할 것인가?

  • 레지스터 (범용 레지스터 / PC / 커널 stack pointer)
  • PCB에 저장해야할 것
    • PID
    • state
    • priority
    • parent - child pid
    • cred
    • open files

 

Concurrency

  • 동시성을 위해서 interrupt handler에 들어갈 때마다 interrupt masking을 하여 interrupt가 중복하여 발생하지 않도록 해야한다.

 

I/O와 같은 느린 operation이 수행될 경우

  • Ready queue: ready 상태 프로세스들의 큐
  • Event queue: I/O나 lock 등과 같이 특정한 event가 끝나길 기다리는 프로세스들을 포함한다. (ex: wait queue)

2. Process API

API: 생성 / 제거 / wait(reaping) / suspend-resume / get status

 

프로세스의 생성

프로세스를 생성하는 데는 두 가지 방법이 존재한다.

 

1. 처음부터 생성

  • 디스크에서 메모리로 프로그램의 code & data 로드.
  • 비어있는 stack 초기화.
  • PCB 초기화. (PCB는 리눅스의 task_struct 구조체에 대응된다고 보면 된다.)
  • 생성한 프로세스를 ready queue에 삽입.
  • 장점: 생성과정의 오버헤드가 적음
  • 단점: 프로세스를 직접 초기화 하기가 매우 까다로움

 

2. 기존 프로세스를 복제한 뒤 내용 변경

이 방법은 fork()와 exec()를 함께 사용한다.

  • fork()
    • 현재 프로세스를 중지하고 state를 save.
    • code / data / stack / PCB의 복사본을 만든다.
    • 복사된 프로세스를 ready queue에 삽입.
  • exec()
    • 현재 프로세스 상의 code와 data를 새롭게 실행할 파일의 것으로 교체
  • 장점: 간단하고 편하고 유연함
  • 단점: copy와 overwrite하는 데 오버헤드가 많이 들어간다.

 

프로세스 생성 과정

  1. 실행할 프로그램의 code segment를 메모리의 프로세스 address space로 로드
  2. Stack을 할당
  3. Heap 생성
  4. 기타 init 작업: I/O setup 등
  5. 새로 생성된 프로세스로 컨트롤을 넘겨줌으로써 program 시작 (main() 함수 실행)

 

프로세스 관리를 위한 자료구조

OS는 프로세스 관리를 위해서 다음과 같은 자료구조를 갖는다.

  • process list(ready queue, block queue, running queue)
  • register context (struct context)
  • PCB / struct proc