운영체제 용어 사전
OS 기초컨텍스트 스위치 비용

시스템 콜

유저 프로그램이 커널에 일을 부탁하는 통로. 모드 전환 비용 때문에 호출 횟수 자체가 성능이 된다.

유저 프로그램이 커널에게 일을 부탁하는 유일한 통로.

왜 모드를 나누나

  • 유저 모드 — 제한된 권한. 자기 주소 공간만 만질 수 있다

  • 커널 모드 — 모든 권한. 하드웨어·다른 프로세스의 메모리에 접근 가능

  • 나누지 않으면

    • 프로그램 하나가 다른 프로그램의 메모리를 읽고 쓸 수 있다
    • 디스크를 직접 지울 수 있다
    • 무한 루프로 CPU 를 영영 붙잡을 수 있다

"아무나 하드웨어를 못 만지게" 가 OS 보호의 출발점이고, CPU가 하드웨어로 이를 강제한다.

어떻게 넘어가나

  • ① 유저 프로그램이 시스템 콜 번호와 인자를 레지스터에 넣는다

  • ② 특별한 명령을 실행한다 (x86-64 는 syscall)

  • ③ CPU 가 커널 모드로 전환하고 정해진 진입점으로 점프한다

  • ④ 커널이 번호를 보고 해당 처리를 한다

  • ⑤ 결과를 반환하며 유저 모드로 돌아온다

  • ③ 이 핵심 — '아무 주소' 로 못 뛴다. 커널이 정한 진입점으로만 들어간다

strace -c ls          # 어떤 시스템 콜을 몇 번 했나
# openat  12   read  8   write  1   close 12 ...

strace -T ls          # 각 호출에 걸린 시간

비용이 있다

모드 전환 자체 + 레지스터 저장·복원 + 캐시·TLB 오염

  • 수백 나노초 ~ 수 마이크로초

함수 호출(수 나노초) 보다 수백 배 비싸다

  • "시스템 콜 횟수를 줄이는 것" 이 그대로 최적화가 된다
// ❌ 1바이트씩 100만 번 → 시스템 콜 100만 번
for (int i = 0; i < 1000000; i++) write(fd, &buf[i], 1);

// ✅ 버퍼에 모았다 한 번에 → 시스템 콜 몇 번
write(fd, buf, 1000000);

표준 라이브러리의 버퍼링(printf·BufferedWriter)이 존재하는 이유가 이것이다.

네 가지 추상화

OS 가 하드웨어를 가려 주는 것
  CPU     → 프로세스 (혼자 쓰는 것처럼)
  메모리  → 가상 주소 공간 (연속된 큰 공간인 것처럼)
  디스크  → 파일 (이름 붙은 바이트 나열인 것처럼)
  장치    → 파일 인터페이스 (리눅스는 거의 모든 것이 파일)

면접 함정

  • "시스템 콜은 함수 호출과 같다" → 모드 전환이 끼어 수백 배 비싸다.
  • "라이브러리 함수 = 시스템 콜"printf는 버퍼가 찰 때만 write를 부른다.

vDSO — 시스템 콜을 안 하는 시스템 콜

gettimeofday(&tv, NULL);     // 시간을 묻는다 — 매우 자주 불린다

매번 커널로 들어가면 비싸다

  • 커널이 '시간 정보가 담긴 페이지' 를 유저 공간에 읽기 전용으로 매핑해 둔다
  • 그 함수는 모드 전환 없이 그 페이지를 읽고 끝난다 (vDSO)

"자주 불리고 읽기만 하는 것" 을 커널 밖으로 빼는 최적화다

cat /proc/<pid>/maps | grep vdso
strace -e trace=all ./app 2>&1 | grep gettimeofday   # 안 잡힌다 (진짜 시스템 콜이 아니므로)

배치로 줄이는 방향

  • readv / writev — 여러 버퍼를 한 번의 호출로 (scatter-gather)

  • sendfile — 디스크 → 소켓을 유저 공간을 거치지 않고 (zero-copy)

  • io_uring — 여러 요청을 링 버퍼에 쌓아 한 번에 제출한다

    • 극단적으로는 시스템 콜 없이도 I/O 가 진행된다
  • 방향이 일관된다 — 호출 횟수를 줄이고 복사를 줄인다

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — OS의 추상화 — 커널/유저 모드·시스템 콜