kernel을 공부할 때 system call, user mode, thread, virtual memory, VFS를 따로 정의하면 실제 실행 흐름이 잘 보이지 않는다. 한 번의 file read를 기준으로 보면 이 개념은 연결된다. user process가 library API를 호출하고, 필요할 때 syscall로 kernel에 진입하며, scheduler와 memory mapping, VFS·filesystem·page cache를 거쳐 결과를 받는다.
이 글은 전체 kernel 구현을 ‘완전 정복’한다는 약속 대신, 다음 학습에서 길을 잃지 않기 위한 boundary map을 만든다.
Kernel이 책임지는 경계
Linux kernel은 privileged mode에서 실행되며 다음 자원을 중재한다.
- task scheduling과 CPU time
- virtual address space와 physical memory
- file descriptor와 filesystem namespace
- network protocol stack과 device
- process credential, isolation, access control
- interrupt와 device I/O
kernel mode가 ‘무엇이든 안전하게 할 수 있는 모드’라는 뜻은 아니다. 권한이 큰 만큼 kernel bug의 영향도 크다. user/kernel privilege separation과 validation이 system safety의 핵심 경계다.
System Call: User Space에서 Kernel Service를 요청한다
application은 일반 function call처럼 libc wrapper를 호출할 수 있지만, kernel entry에서는 architecture에 맞는 syscall instruction과 ABI를 사용한다. 예전 설명의 ‘system call interrupt’는 일부 architecture·역사적 구현을 떠올리는 표현이며 모든 현대 Linux syscall entry를 뜻하지 않는다.
application code
→ language runtime / libc wrapper
→ syscall instruction + ABI
→ kernel entry and argument validation
→ subsystem work
→ return value or errno
→ user mode resumes
mode switch와 context switch는 다르다. 한 task가 syscall을 수행하고 같은 task로 돌아오면 privilege mode는 바뀌지만 다른 task로 CPU execution context가 넘어갔다고 볼 수는 없다. syscall 중 block되거나 preemption되면 scheduler가 다른 task를 실행할 수 있다.
Python open() 한 줄에서 일어날 수 있는 일
with open("example.txt", "r", encoding="utf-8") as file:
data = file.read()
이 코드는 high-level buffered text I/O다. runtime은 path를 열 때 openat 계열 syscall을 사용하고, buffer를 채우기 위해 read를 여러 번 또는 한 번 호출할 수 있다. 실제 byte가 storage device에서 매번 읽힌다고 단정할 수 없다. page cache에 data가 있으면 device I/O 없이 반환될 수 있고, readahead와 filesystem behavior도 호출 수를 바꾼다.
관찰하려면 추측 대신 실행 환경에서 확인한다.
strace -f -e trace=%file,read,write python3 example.py
strace는 timing과 behavior에 영향을 줄 수 있고 path·argument에 민감 정보가 포함될 수 있으므로 production 사용 범위를 제한한다.
Process와 Thread를 Linux Task 관점에서 보기
Linux scheduler가 다루는 execution entity는 흔히 task라고 부른다. user space에서 process와 thread를 구분하지만 kernel 내부에서는 task_struct로 표현되는 task들이 어떤 resource를 공유하는지에 따라 관계가 만들어진다.
- 같은 process의 thread들은 보통 virtual address space, open-file table 등 여러 resource를 공유한다.
- 각 thread는 stack, register state, scheduling state와 thread ID를 가진다.
- process ID와 thread group ID, PID namespace에서 보이는 ID를 구분해야 한다.
fork,clone,execve는 생성·공유·program replacement의 서로 다른 경계다.
Python threading.Thread 예제만으로 OS thread의 병렬성을 일반화하지 않는다. CPython build와 workload에 따라 GIL의 영향이 있고, blocking I/O와 CPU-bound Python code의 실행 특성이 다르다. 실제 thread 수, CPU scheduling, lock wait를 함께 관찰한다.
Scheduler와 Context Switch
running task가 block되거나 time slice·priority·wakeup 조건에 따라 scheduler가 다른 runnable task를 선택할 수 있다. context switch에서는 register와 execution state를 바꾸고, address-space switch가 동반될 때 page-table·TLB 관련 비용도 생길 수 있다.
모든 kernel entry가 context switch를 일으키거나 모든 context switch가 비정상은 아니다. 다음을 구분한다.
- voluntary switch: I/O, sleep, lock wait처럼 task가 기다릴 때
- involuntary switch: preemption 등으로 CPU를 넘길 때
- runnable queue delay: 실행 가능하지만 CPU를 기다리는 시간
counter 하나보다 workload와 latency, CPU saturation을 같은 timeline에서 본다.
Virtual Memory는 ‘RAM보다 큰 Memory’만이 아니다
virtual memory는 process가 사용하는 virtual address를 physical memory와 file, shared mapping 등에 연결하는 abstraction이다. 핵심 가치는 capacity 확장만이 아니라 isolation, protection, sharing, sparse address space다.
virtual address
→ VMA permission and mapping
→ page table
→ physical page or not-present entry
→ MMU / TLB translation
translation이 준비되지 않았거나 permission check가 필요한 access는 page fault를 낼 수 있다.
- minor fault는 필요한 page를 storage에서 새로 읽지 않고 해결할 수 있다.
- major fault는 backing storage I/O가 필요할 수 있어 latency가 훨씬 클 수 있다.
- invalid access는 mapping을 만들지 못하고 signal로 이어질 수 있다.
swap은 virtual memory의 필수 정의가 아니며 system과 cgroup 설정에 따라 없을 수 있다. memory pressure에서는 free 값 하나보다 available memory, working set, reclaim, page fault, PSI, swap, OOM event를 함께 본다.
VFS가 File API를 연결하는 방식
VFS는 application에 공통 file model을 제공하고 ext4, XFS, tmpfs, NFS 같은 filesystem implementation으로 operation을 dispatch하는 kernel layer다.
path lookup에는 여러 object와 cache가 관여한다.
- superblock: mounted filesystem의 전체 metadata
- inode: file object의 metadata와 operation
- dentry: pathname component와 inode 연결을 cache
- file: open instance와 file offset·operation state
open() 시 path lookup으로 dentry·inode를 찾고 permission을 검사한 뒤 file descriptor를 반환한다. read()는 fd가 가리키는 open file을 통해 filesystem과 page cache에서 data를 얻는다. VFS가 요청을 직접 ‘모두 처리’하는 것이 아니라 공통 interface와 object model을 제공하고 filesystem·driver가 구체적 operation을 구현한다.
file에 write()한 뒤 process buffer, kernel page cache, filesystem journal, storage cache의 durability 시점도 다를 수 있다. crash consistency가 필요하면 temp file, fsync, atomic rename, directory fsync 같은 protocol을 filesystem 보증과 함께 설계한다.
한 번의 Read를 다시 연결하면
- user code가 runtime의 file API를 호출한다.
- runtime은 buffering 상태에 따라 syscall이 필요한지 판단한다.
- task가 syscall instruction으로 kernel mode에 진입한다.
- kernel은 fd, buffer address, permission을 검증한다.
- VFS가 open file의 filesystem read path로 요청을 전달한다.
- page cache hit면 memory에서 복사하고, miss면 I/O를 시작해 task가 block될 수 있다.
- scheduler가 다른 runnable task를 실행할 수 있다.
- I/O completion 뒤 task가 깨어나고 data가 user buffer로 전달된다.
- syscall이 return하고 runtime이 decoding·buffering을 마무리한다.
실제 path는 filesystem, direct I/O, async I/O, mmap 여부에 따라 달라진다. 이 순서는 mental model이지 모든 read의 고정 trace가 아니다.
system call 이름과 세부 경계는 Linux system call 이름 읽는 법, CPU·memory의 기초는 CPU와 Memory 기본 개념으로 이어갈 수 있다.
자주 묻는 질문
System call을 하면 항상 다른 process로 context switch되나
아니다. user mode에서 kernel mode로 진입하는 mode switch와 scheduler가 다른 task를 선택하는 context switch는 별개다.
File을 읽으면 항상 disk I/O가 발생하나
아니다. page cache hit, filesystem, direct I/O 여부에 따라 다르다. syscall trace와 block-I/O·page-cache 지표로 확인한다.
Virtual memory는 RAM이 부족할 때 disk를 쓰는 기능인가
그것만이 아니다. address translation, isolation, protection, sharing이 핵심이며 swap은 가능한 backing mechanism 중 하나다.
참고 자료
'배움과 성장 > 시스템·성능' 카테고리의 다른 글
| 프로세스 메모리 구조: 힙·스택·가상 메모리 도식의 한계 (0) | 2024.12.07 |
|---|---|
| Linux CPU 실행 경로: 시스템 콜·하드 IRQ·softirq·workqueue 구분 (2) | 2024.12.06 |
| Linux man 페이지 섹션과 syscall 추적: man 1·2·3·5·7·8 (5) | 2024.12.06 |
| JIT 컴파일과 가상 머신: bytecode·ISA·profiling·deoptimization 구분 (0) | 2024.12.05 |
| Linux free 읽는 법: available·page cache·slab·dentry 구분하기 (1) | 2024.11.25 |
댓글