clone 시스템 콜 (clone System Call)
Ⅰ. 개요
1. 정의
clone 시스템 콜은 리눅스에서 프로세스와 스레드 생성을 모두 수행하는 통합 API이다. fork()와 pthread_create()의 기반이 되는 저수준 시스템 콜로, 플래그 설정을 통해 부모와 자식 간의 자원 공유 수준을 세밀하게 제어할 수 있다.
clone의 위치와 역할
┌─────────────────────────────────────────────────┐
│ 사용자 수준 API │
│ ┌──────────┐ ┌────────────────────┐ │
│ │ fork() │ │ pthread_create() │ │
│ └────┬─────┘ └─────────┬──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ clone() 시스템 콜 │ │
│ │ (리눅스 유일 생성 인터페이스) │ │
│ └──────────────────────────────────┘ │
│ 커널 수준 │
└─────────────────────────────────────────────────┘
비유: clone은 "부모의 물건 중 어떤 것을 공유하고 어떤 것을 새로 만들지 선택할 수 있는 이사 계약서"와 같다. fork는 "물건을 모두 복사해서 새 집으로 이사"하고, pthread_create는 "물건을 모두 공유하면서 같은 집에서 함께 사는 것"이다.
Ⅱ. clone 시스템 콜 인터페이스
1. 함수 원형
long clone(unsigned long flags, void *child_stack,
int *ptid, int *ctid,
unsigned long newtls);
| 매개변수 | 설명 |
|---|---|
flags | 공유/복제 동작 제어 플래그 |
child_stack | 자식이 사용할 새 스택 포인터 |
ptid | 부모 스레드 ID 저장 위치 |
ctid | 자식 스레드 ID 저장 위치 (CLONE_CHILD_SETTID) |
newtls | 새 TLS (Thread Local Storage) 주소 |
2. 주요 CLONE_* 플래그
clone 플래그와 자원 공유 범위
┌──────────────┬────────────────────────────────────┐
│ 플래그 │ 공유하는 자원 │
├──────────────┼────────────────────────────────────┤
│ CLONE_VM │ 메모리 공간 (Address Space) │
│ CLONE_FS │ 파일 시스템 정보 (root, cwd, umask) │
│ CLONE_FILES │ 파일 디스크립터 테이블 │
│ CLONE_SIGHAND│ 시그널 핸들러 │
│ CLONE_THREAD │ 스레드 그룹 (동일 TGID) │
│ CLONE_PARENT │ 부모와 같은 부모를 가짐 │
│ CLONE_PTRACE │ 디버거 추적 공유 │
│ CLONE_SETTLS │ 새 TLS 영역 설정 │
└──────────────┴────────────────────────────────────┘
Ⅲ. fork()와 pthread_create()의 clone 매핑
1. fork() = clone(최소 공유)
fork()의 clone 호출 (실제 구현 개념)
┌─────────────────────────────────────────────────┐
│ │
│ fork() ≈ clone(SIGCHLD, child_stack) │
│ │
│ 결과: │
│ ┌─────────┐ ┌─────────┐ │
│ │ 부모 │ │ 자식 │ │
│ │ 메모리 │ ─ 복사 ─→│ 메모리 │ (CLONE_VM X)│
│ │ 파일테이블│─ 복사 ─→│ 파일테이블│ (CLONE_FILES X)│
│ │ 스택 │ ─ 복사 ─→│ 스택 │ │
│ │ 시그널 │ ─ 복사 ─→│ 시그널 │ (CLONE_SIGHAND X)│
│ └─────────┘ └─────────┘ │
│ │
│ ★ 거의 모든 것이 독립적인 사본 │
└─────────────────────────────────────────────────┘
2. pthread_create() = clone(모든 공유)
pthread_create()의 clone 호출 (실제 구현 개념)
┌─────────────────────────────────────────────────┐
│ │
│ pthread_create() ≈ clone( │
│ CLONE_VM | CLONE_FS | CLONE_FILES | │
│ CLONE_SIGHAND | CLONE_THREAD | │
│ CLONE_SETTLS | CLONE_PARENT_SETTID | │
│ CLONE_CHILD_CLEARTID, child_stack) │
│ │
│ 결과: │
│ ┌─────────┐ ┌─────────┐ │
│ │ 스레드 A│ │ 스레드 B│ │
│ │ 메모리 │ ─ 공유 ─→│ 메모리 │ (CLONE_VM O)│
│ │ 파일테이블│─ 공유 ─→│ 파일테이블│ (CLONE_FILES O)│
│ │ 시그널 │ ─ 공유 ─→│ 시그널 │ (CLONE_SIGHAND O)│
│ │ 스택 │ 독립 │ 스택 │ (각자의 스택)│
│ └─────────┘ └─────────┘ │
│ │
│ ★ 메모리/파일/시그널 공유, 스택만 독립 │
└─────────────────────────────────────────────────┘
3. fork() vs clone() vs pthread_create() 비교
자원 공유 비교표
┌────────────────┬─────────┬──────────────┬──────────────┐
│ 자원 │ fork() │ clone() │pthread_create│
├────────────────┼─────────┼──────────────┼──────────────┤
│ 메모리 공간 │ 복사 │ 플래그로 결정 │ 공유 │
│ 파일 디스크립터│ 복사 │ 플래그로 결정 │ 공유 │
│ 파일시스템정보 │ 복사 │ 플래그로 결정 │ 공유 │
│ 시그널 핸들러 │ 복사 │ 플래그로 결정 │ 공유 │
│ 스택 │ 복사 │ 새 스택 필수 │ 새 스택 필수 │
│ PID │ 새 PID │ 새 PID │ 새 TID │
│ 유연성 │ 낮음 │ 최고 │ 중간 │
└────────────────┴─────────┴──────────────┴──────────────┘
Ⅳ. CLONE_* 플래그 상세
1. CLONE_VM (Virtual Memory)
CLONE_VM의 메모리 공유
┌─────────────────────────────────────────────────┐
│ CLONE_VM 설정 시 (스레드 생성): │
│ │
│ 부모 task_struct ──┐ │
│ ├──→ mm_struct (공유) │
│ 자식 task_struct ──┘ │
│ │
│ CLONE_VM 미설정 시 (fork): │
│ │
│ 부모 task_struct ──→ mm_struct A │
│ 자식 task_struct ──→ mm_struct B (사본) │
└─────────────────────────────────────────────────┘
2. CLONE_FS / CLONE_FILES / CLONE_SIGHAND
- CLONE_FS: root 디렉토리, 작업 디렉토리, umask를 공유
- CLONE_FILES: 열린 파일 디스크립터 테이블을 공유
- CLONE_SIGHAND: 시그널 디스포지션(핸들러)과 보류/차단 시그널을 공유
3. CLONE_THREAD
CLONE_THREAD와 스레드 그룹
┌─────────────────────────────────────────────────┐
│ │
│ CLONE_THREAD 설정 시: │
│ ┌──────────────────────────────────┐ │
│ │ 스레드 그룹 (TGID: 1000) │ │
│ │ │ │
│ │ TID 1000 ←─ 리더 스레드 │ │
│ │ TID 1001 ←─ CLONE_THREAD 생성 │ │
│ │ TID 1002 ←─ CLONE_THREAD 생성 │ │
│ │ │ │
│ │ ★ 모두 동일 TGID = 1000 │ │
│ │ ★ getpgrp(), getppid() 공유 │ │
│ │ ★ 하나가 exit() 시 전체 종료 │ │
│ └──────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
Ⅴ. 지식 그래프 및 요약
1. 지식 그래프
[clone 시스템 콜]
├── [상위 API]
│ ├── fork() ─── SIGCHLD만 설정 (최소 공유)
│ ├── vfork() ── CLONE_VFORK | CLONE_VM (메모리 완전 공유)
│ └── pthread_create() ── 모든 CLONE_* 플래그 설정
├── [공유 제어 플래그]
│ ├── CLONE_VM ────── 메모리 공간
│ ├── CLONE_FS ────── 파일시스템 정보
│ ├── CLONE_FILES ─── 파일 디스크립터
│ ├── CLONE_SIGHAND ── 시그널 핸들러
│ └── CLONE_THREAD ── 스레드 그룹 (TGID)
├── [독립 자원]
│ ├── PID/TID
│ ├── 스택 (항상 새로 할당)
│ └── 레지스터 상태
└── [특수 변형]
├── CLONE_UNTRACED ─── 추적 방지
└── CLONE_NEWNS ────── 새 마운트 네임스페이스
2. 준말
- TLS: Thread Local Storage (스레드 로컬 저장소)
- TGID: Thread Group ID (스레드 그룹 식별자)
- TID: Thread ID (스레드 식별자)
3. 어린이를 위한 3줄 설명
clone은 새로운 프로세스나 스레드를 만들 때 "부모의 것 중 어떤 것을 같이 쓰고 어떤 것을 새로 만들지" 선택할 수 있는 마법의 복사기예요. fork는 "모든 물건을 똑같이 복사해서 새 집에 사는 것"이고, 스레드는 "방만 따로 쓰고 나머지는 다 같이 쓰는 것"이에요. 이 하나의 명령어로 리눅스의 프로세스와 스레드를 모두 만들어낼 수 있어요.