*이 글은 Operating Systems: Three Easy Pieces(운영체제 아주 쉬운 세 가지 이야기)를 바탕으로 작성되었습니다. 첨부한 모든 그림은 해당 도서에서 가져온 자료입니다. 내용 중 잘못된 부분이 있다면 알려주세요 :)
우리는 여러 프로그램을 동시에 실행하길 원한다.
운영체제는 여러 프로그램들이 실행되는 것처럼 환상을 만들어(CPU를 가상화), 이를 가능하게 만든다.
이 과정에서의 운영체제의 핵심 개념 중 하나는 프로세스이다.
프로세스는 현재 실행 중인 프로그램으로 정의된다.
하나의 프로세스를 실행하고, 중단하고 다른 프로세스를 scheduling하여 실행을 반복하며, 실제로 여러 프로그램이 실행되고 있다고 느끼게 만든다.
이를 time-sharing이라고 하며, 하나의 프로세스를 중단하고 다른 프로세스를 실행하는 것을 context switch라고 한다.
🧐 Process란 무엇인가
위에서 말했듯이
process는 실행 중인 program이다.
특정한 순간의 프로세스를 표현하기 위해선, 실행되는 동안 접근했거나 영향받은 자원의 목록을 보면 된다.
이 프로세스의 구성요소를 이해하기 위해선 하드웨어 상태(machine state)를 이해해야 한다.
프로그램이 실행될 동안 읽거나 업데이트 할 수 있는 하드웨어 영역은 Memory, Register이다.
Memory
- 프로세스의 하드웨어 상태 중 가장 중요한 요소
- 명령어, 실행 프로그램이 읽고 쓰는 데이터는 메모리에 저장된다.
Register
- program counter(PC): 프로그램의 어느 명령어가 실행 중인지 알려줌
- stack pointer, frame pointer: 함수의 변수와 리턴 주소를 저장하는 스택 관리
🧐 Program 대략적인 실행 과정
프로그램이 어떻게 프로세스가 되는가?
그 과정을 살펴보자.
- 프로그램 code, static data를 메모리(process의 address space 위치)에 로딩
- OS가 stack, heap을 위한 영역 할당, 초기화
- 입출력과 관계된 초기화 작업 수행
- main() 루틴으로 분기함으로써 CPU를 새로 생성된 프로세스에게 넘김
🧐 Process의 상태
- 실행 (Running): 실행 중인 프로세스
- 준비 (Ready): 실행 준비가 된 프로세스, 다른 프로세스를 실행 중 등의 이유로 대기 중
- 대기 (Blocked): 사건을 기다리는 동안 수행 중단 중인 프로세스
두 개의 프로세스를 실행한다고 가정하고 예를 살펴보자.
Process0이 Running 상태로 실행되는 동안 Process1은 Ready 상태이고, 끝난 뒤 Process1이 Running 상태로 변한다.
I/O도 고려하여 생각해보자
Process0이 Running 상태로 실행되다가 입출력을 요청하여 Blocked 상태가 되고, Ready였던 Process1이 싱행되게 된다.
입출력 입력 받으면 Process1은 Ready 상태로 변하고, Process1이 끝난 뒤 다시 실행된다.
위 예시의 상황에서 Process0, Process1을 언제, 어떤 순서로 실행할지 결정은 성능이 큰 영향을 미친다.
이 결정을 내리는 것이 바로 스케줄러이다. (추후 배우는 내용,,)
🧐 Process의 자료구조
위는 xv6 커널에서의 프로세스 구조이다.
(xv6는 교육용 커널로, 실제 Linux, Mac OS, Window 등은 더 복잡하다고 합니다...!)
- register context
struct context {
int eip;
int esp;
int ebx;
int ecx;
int edx;
int esi;
int edi;
int ebp;
};
- 프로세스가 중단되었을 때 해당 프로세스의 레지스터 값들을 저장한다.
- 이 레지스터 값들을 복원하여, 운영체제는 프로세스 실행을 재개한다.
=> context switch
- process state
enum proc_state {UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE}
(OS마다 조금씩 상태가 다르다고 합니다)
- process info
- PCB(Process Control Block)
struct proc {
char *mem; //프로세스 메모리 시작 주소
uint sz; // 프로세스 메모리의 크기
char *kstack; // 이 프로세스의 커널 스택의 바닥 주소
enum proc_state state; // 프로세스 상태
int pid; // 프로세스 id
struct proc *parent; // 부모 프로세스
void *chan; // 0이 아니면, chan에서 수면
int killed; // 0이 아니면, 종료
struct file *ofile[NOFILE]; // 열린 파일
struct inode *cwd; // 현재 디렉토리
struct context context; // 프로세스를 실행시키려면 교환
struct trapframe *tf; // 현재 인터럽트에 해당하는 trapframe
};
이번 글은 사실상 CPU 가상화를 알기위해
process의 개념을 다져본 것이고, 진짜는 다음부터!
더 구체적으로 프로세스 구현과 위에서 언급했던 스케줄링에 대해 차차 알아보자.
'기본 > 운영체제' 카테고리의 다른 글
[OS] 메모리 가상화(Memory Virtualization): 6. Paging: TLB (0) | 2024.05.25 |
---|---|
[OS] CPU 가상화 (CPU Virtualization): 2. Limited Direct Execution: time sharing, context switch (1) | 2024.04.20 |
[OS] 메모리 가상화(Memory Virtualization): 5. Paging: 개요 (2) | 2024.04.20 |
[OS] 메모리 가상화(Memory Virtualization): 4. Free-Space Management (0) | 2024.04.19 |
[OS] 메모리 가상화 (Memory Virtualization): 3. Segmentation (1) | 2024.04.12 |