CPU 가상화와 프로세스: OSTEP 기반 고급 요약
- 가상화의 목표: 소수의 물리 CPU로 다수의 가상 CPU 환상 제공(타임셰어링). 정책(policy)과 메커니즘(mechanism)을 분리해 설계.
- 프로세스: 실행 중인 프로그램 + 주소공간/레지스터/열린 FD/프로세스 상태 등 머신 상태의 집합. 러닝↔레디↔블록드 상태 전이를 가진다.
- API:
fork(복제/COW) +exec(프로그램 교체) +wait(동기화)로 셸의 리다이렉션·파이프 구현까지 가능. - LDE: 사용자/커널 모드, 트랩(syscall), 타이머 인터럽트(선점), 컨텍스트 스위치로 성능과 제어를 동시에 달성.
1) 프로세스 추상화
정의 & 정신모델
프로세스는 “실행 중인 프로그램”으로, 주소공간(코드/데이터/힙/스택), 레지스터(PC, SP 등), 열린 파일 등의 머신 상태로 기술된다. OS는 타임셰어링으로 다수의 프로세스를 교대로 실행해 다수의 CPU가 있는 것처럼 보이게 한다. 정책(스케줄링)과 메커니즘(컨텍스트 스위치)을 분리한다.
프로세스 생성: 프로그램→프로세스
- 코드/정적 데이터 로드(과거 eager, 현대 lazy), 스택 초기화(argc/argv), 힙 준비(
malloc/free). - 기본 FD(표준 입출력 3종) 세팅 →
main()진입.
상태(State)와 전이
- Running: CPU 위에서 실행 중
- Ready: 실행 준비 완료(스케줄 대기)
- Blocked: I/O 등 이벤트 대기
Running ⇄ Ready
↓ I/O
Blocked → Ready (I/O 완료)
↓ I/O
Blocked → Ready (I/O 완료)
커널의 데이터구조
PCB(혹은 task 구조체)에 레지스터 컨텍스트, 상태, PID, 열린 파일, 커널스택, 트랩프레임 등을 유지한다.
2) UNIX Process API: fork/exec/wait
핵심 콤비
fork(): 현재 프로세스를 COW로 가볍게 복제. 부모는 자식 PID, 자식은 0을 반환. 스케줄링에 따라 출력 순서 비결정적.wait()/waitpid(): 부모가 자식 종료를 기다려 결정적 순서 보장.exec*(): 현재 프로세스의 코드/정적데이터/스택/힙을 새 실행파일로 교체. 성공 시 복귀하지 않음.
셸이 이 조합을 사랑하는 이유
- 리다이렉션:
fork후 자식에서close(STDOUT)→open("file")→exec로 표준출력을 파일에 결선. - 파이프:
pipe()로 두 프로세스의 표준 입/출력을 커널 파이프로 연결.grep -o foo file | wc -l같은 조합 구현. - 시그널/권한: 사용자 격리, root 권한,
kill/killall,signal()로 핸들러.
3) Limited Direct Execution: 트랩·타이머·컨텍스트 스위치
아이디어
가능한 한 직접 실행해 성능을 얻고(사용자 모드), 필요한 순간에만 제한(limit)을 걸어 커널이 통제한다(커널 모드).
특권 분리와 시스템콜
- 사용자 모드에서는 특권 연산(I/O, MMU 등) 금지. 위반 시 예외.
- 트랩: 라이브러리 래퍼가 번호/인자 셋업 → trap → 커널 핸들러 → return-from-trap으로 복귀. 트랩 테이블은 부팅 시 커널이 등록.
선점 스케줄링의 열쇠: 타이머 인터럽트
비협조적 프로세스가 시스템콜을 안 해도 타이머 인터럽트로 커널이 CPU를 회수 → 스케줄러가 전환 결정 → 컨텍스트 스위치 실행.
timer interrupt → save regs(A) → kernel → switch(A→B) → return-from-trap → run B
컨텍스트 스위치
하드웨어가 트랩 시 사용자 레지스터를 커널스택에 저장, 커널이 switch()에서 커널 레지스터/스택을 다른 프로세스로 교체 후 복귀.
보안 주의: 시스템콜 경계에서 유저 인자를 철저히 검증해야 커널/타 프로세스 메모리 유출을 막을 수 있다.
4) 프로세스 vs 스레드 (초간단 비교)
| 측면 | 프로세스 | 스레드 |
|---|---|---|
| 주소공간 | 분리(격리) | 공유 |
| 생성/전환 | 무겁다(CR3/TLB 영향) | 가볍다(동일 VAS) |
| 통신 | IPC 필요 | 메모리 직접 공유(동기화 필요) |
| 격리/보안 | 우수 | 취약(프로세스 전체 영향) |
5) 핵심 예제 & 실습
fork + wait (순서 보장)
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
int main(){
pid_t pid=fork();
if(pid==0){ puts("child"); }
else if(pid>0){ wait(NULL); puts("parent"); }
else { perror("fork"); }
}
리다이렉션: stdout → 파일
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
int main(){
if(fork()==0){
close(1);
open("out.txt", O_CREAT|O_WRONLY|O_TRUNC, 0644);
execlp("wc","wc","main.c",(char*)0);
} else { wait(NULL); }
}
연습 문제
- 프로세스의 머신 상태를 구성하는 요소를 열거하고, 각 요소가 어디에 저장되는지 설명하라.
fork후wait이 순서를 결정적으로 만드는 이유를 설명하라.- 트랩/리턴-프롬-트랩, 타이머 인터럽트가 선점과 제어에 기여하는 과정을 단계별로 서술하라.
정답 보기 (펼치기/접기)
1) 프로세스의 머신 상태 & 저장 위치
- 주소 공간 (코드/데이터/힙/사용자 스택): 프로세스의 가상 메모리에 존재. 물리 프레임 매핑은 페이지 테이블이 관리.
- 레지스터 집합 (PC, SP, GPR, FLAGS 등): 실행 중엔 CPU 레지스터에, 트랩/컨텍스트 스위치 시엔 커널이 커널 스택과 PCB(Task/Proc 구조)에 저장.
- 페이지 테이블/메모리 맵: 커널 내 프로세스 메모리 디스크립터(mm 구조체 등)와 하드웨어 PT에 반영. 프로세스 전환 시 CR3/TTBR 전환.
- 열린 파일 테이블(FD 테이블): 프로세스별 커널 객체(파일 디스크립터 테이블). 각 엔트리는 오픈-파일 설명자(오프셋/플래그)와 vnode/inode를 가리킴.
- 신호/마스크/핸들러: 커널의 per-process/ per-thread 구조체에 저장.
- 커널 스택: 각 (커널에서 스케줄되는) 스레드마다 존재. 트랩 시 HW가 사용자 문맥 일부를 여기에 푸시.
- 자격/리소스 한도 (UID/GID, rlimit, cgroup 등): 커널의 작업 구조체에 보관.
- 스케줄링 정보 (상태/우선순위/실행시간): 런큐 & PCB에 유지.
2) fork 후 wait이 순서를 결정적으로 만드는 이유
fork() 직후 부모·자식은 동시에 실행돼 출력 순서가 비결정적이다. 부모가 wait()를 호출하면 커널은 부모를 블록하고, 자식이 종료 상태가 될 때까지 깨워주지 않는다(SIGNAL/자식 상태 변화). 자식 종료 후 부모가 깨어나 순차적으로 진행하므로 “항상 자식 → 부모” 같은 결정적 순서를 보장할 수 있다.
3) 트랩/리턴-프롬-트랩 & 타이머 인터럽트의 단계
- 시스템 콜 진입(트랩): 사용자 코드가 래퍼를 통해 번호/인자를 레지스터/스택에 세팅 →
syscall/int 0x80/svc실행. - 권한 전환: HW가 커널 모드로 전환, 커널 스택 포인터로 스택을 바꾸고 사용자 레지스터를 커널 스택에 자동 저장.
- 핸들러 실행: 커널이 인자 검증·자원 액세스 수행. 필요 시 스케줄러를 호출하여 다른 태스크로 전환.
- 리턴-프롬-트랩: 커널이 저장한 레지스터를 복원,
iret/sysret/eret로 사용자 모드로 귀환. - 타이머 인터럽트: 주기적으로 발생해 커널로 트랩 → 현재 태스크의 커널 문맥 저장 → 스케줄러가 선점 판단 시 현재 태스크의 컨텍스트를 PCB에 저장하고 다음 태스크의 문맥을 로드 → 리턴-프롬-트랩으로 선택된 태스크가 재개.
요점: 트랩은 “사용자→커널” 제어 이전, 타이머는 커널이 주기적으로 CPU를 회수하여 선점을 실현한다.
7) 치트시트
- 상태 전이: Running⇄Ready, Running→Blocked(I/O), Blocked→Ready(완료)
- API:
fork(복제,COW) →exec(교체,복귀X) →wait(동기화) - LDE: 사용자/커널 모드, 트랩, 트랩테이블, 타이머, 컨텍스트 스위치