본문 바로가기
카테고리 없음

OS - 시스템콜, 커널모드, 이중모드

by kik328288 2026. 5. 27.

시스템 콜 (커널 모드, 이중 모드, 인터럽트)

내가 파이썬으로 open("a.txt") 한 줄을 실행하면, 그 안에서는 사용자 프로그램이 직접 할 수 없는 일이 벌어진다. 디스크라는 하드웨어를 건드리는 일은 운영체제만의 특권이기 때문이다. 사용자 프로그램이 파일을 읽고, 네트워크로 데이터를 보내고, 새 프로세스를 만드는 모든 순간, 프로그램은 운영체제 커널에게 "이 일을 대신 해 달라"고 요청한다. 이 요청의 공식 창구가 시스템 콜(System Call)이다. 본 글은 사용자 모드와 커널 모드를 가르는 이중 모드의 원리, 시스템 콜이 호출되는 과정, 그리고 그것을 떠받치는 인터럽트 메커니즘을 세심하게 정리한다(출처: 위키백과 — System call). 제가 운영체제 수업에서 strace 명령으로 간단한 프로그램 하나가 수백 개의 시스템 콜을 쏟아 내는 것을 처음 본 날, "내가 짠 코드는 빙산의 일각이고 그 아래에서 커널이 끊임없이 일하고 있다"는 사실을 실감했다.

 

이중 모드 — 사용자 모드와 커널 모드

운영체제 보호의 출발점은 CPU가 두 가지 실행 모드를 갖는 이중 모드(dual mode)다. 사용자 모드(user mode)에서는 일반 응용 프로그램이 실행되며, 하드웨어를 직접 제어하는 명령(특권 명령)은 금지된다. 커널 모드(kernel mode)에서는 운영체제 커널이 실행되며, 모든 명령과 모든 메모리 영역에 접근할 수 있다. CPU 안의 모드 비트(mode bit) 하나가 현재 어느 모드인지를 나타낸다.

이 구분이 필요한 이유는 보호와 안정성이다. 만약 모든 프로그램이 하드웨어를 직접 건드릴 수 있다면, 버그 있는 프로그램 하나가 디스크를 망가뜨리거나 다른 프로세스의 메모리를 짓밟아 시스템 전체를 무너뜨릴 수 있다. 그래서 디스크 I/O, 인터럽트 설정, 메모리 관리 레지스터 변경 같은 위험한 명령은 특권 명령(privileged instruction)으로 지정되어 커널 모드에서만 실행되고, 사용자 모드에서 시도하면 CPU가 트랩을 걸어 차단한다.

여기서 핵심 통찰은, 사용자 프로그램이 디스크를 읽고 싶을 때 그 일을 직접 못 한다는 것이다. 대신 "디스크를 읽어 달라"고 커널에 정중히 요청해야 하며, 그 요청의 표준 통로가 시스템 콜이다. 즉 시스템 콜은 사용자 모드에서 커널 모드로 안전하게 건너가는 유일하게 허가된 문이다.

시스템 콜의 호출 과정

시스템 콜이 실제로 어떻게 동작하는지 단계별로 보자. 사용자 프로그램이 read() 같은 라이브러리 함수를 호출하면, 그 함수 내부는 다음 순서로 커널에 진입한다.

[ read() 시스템 콜의 흐름 ]

사용자 모드                    │  커널 모드
───────────────────────────────┼───────────────────────────
1. read() 라이브러리 함수 호출   │
2. 시스템 콜 번호를 레지스터에    │
   적재 (예: read = 0)          │
3. trap/syscall 명령 실행 ──────┼──▶ 4. CPU가 커널 모드로 전환
                               │     모드 비트 = 0
                               │  5. 시스템 콜 테이블에서
                               │     번호로 핸들러 검색
                               │  6. 커널이 실제 디스크 I/O 수행
                               │  7. 결과를 레지스터에 저장
8. 반환값 수신 ◀───────────────┼── 사용자 모드로 복귀

핵심은 3번의 트랩(trap) 명령이다. 이 특수 명령이 실행되면 CPU는 자동으로 커널 모드로 전환하고, 미리 정해진 커널의 진입점으로 점프한다. 커널은 레지스터에 담긴 시스템 콜 번호를 보고 시스템 콜 테이블에서 해당 핸들러를 찾아 실행한다. 사용자가 직접 커널 코드의 임의 위치로 뛰어드는 것이 아니라, 오직 번호를 통해 정해진 진입점으로만 들어갈 수 있다는 점이 보안의 핵심이다. 작업이 끝나면 모드 비트를 다시 사용자 모드로 되돌리고 결과와 함께 원래 프로그램으로 복귀한다.

시스템 콜은 기능별로 분류된다. 프로세스 제어(fork, exec, exit), 파일 조작(open, read, write, close), 장치 관리, 정보 유지(getpid, time), 그리고 통신(pipe, socket)이 대표적인 다섯 범주다. 우리가 쓰는 printf 한 줄도 내부적으로는 write 시스템 콜로 귀결되며, 고수준 언어의 거의 모든 입출력이 결국 이 좁은 시스템 콜 집합으로 모인다.

인터럽트와 시스템 콜 — 커널이 깨어나는 방식

시스템 콜을 더 깊이 이해하려면 그것이 인터럽트(interrupt) 메커니즘 위에 올라타 있음을 알아야 한다. 인터럽트란 CPU가 현재 하던 일을 잠시 멈추고 특정 처리 루틴으로 즉시 이동하게 만드는 신호다. 인터럽트는 발생 원인에 따라 크게 두 종류로 나뉜다.

구분 발생 원인 예시 동기/비동기
하드웨어 인터럽트 외부 장치 키보드 입력, 디스크 완료, 타이머 비동기
소프트웨어 인터럽트(트랩) 실행 중인 명령 시스템 콜, 0 나누기, 페이지 폴트 동기

시스템 콜은 이 중 소프트웨어 인터럽트(트랩)에 해당한다. 프로그램이 의도적으로 트랩 명령을 실행해 스스로 커널을 깨우는 것이다. 반면 키보드를 누르거나 디스크 읽기가 끝나는 것은 프로그램과 무관하게 외부에서 비동기적으로 발생하는 하드웨어 인터럽트다. 두 경우 모두 CPU는 현재 상태(레지스터·프로그램 카운터)를 저장하고, 인터럽트 벡터 테이블에서 해당 처리 루틴(ISR)의 주소를 찾아 실행한 뒤, 끝나면 저장한 상태를 복원해 원래 흐름으로 돌아간다.

여기서 성능과 관련한 중요한 사실 하나가 있다. 시스템 콜은 모드 전환과 상태 저장·복원 때문에 일반 함수 호출보다 훨씬 비싸다(보통 수백~수천 사이클). 그래서 고성능 프로그램은 시스템 콜 횟수를 줄이는 것이 핵심 최적화다. 예컨대 1바이트씩 천 번 write하는 대신 1KB를 버퍼에 모아 한 번에 write하는 버퍼링이 그것이며, 표준 라이브러리의 BufferedWriter가 바로 이 일을 한다.

흔한 오해 하나를 짚으면 "시스템 콜과 일반 함수 호출은 비슷하다"는 통념인데, 일반 함수 호출은 같은 사용자 모드 안에서 일어나지만 시스템 콜은 모드 전환을 동반하는 근본적으로 비싼 연산이다. 또 하나, "커널 모드가 사용자 모드보다 빠르다"는 오해도 흔한데, 모드 자체에 속도 차이가 있는 것이 아니라 권한의 차이일 뿐이며, 오히려 모드를 오가는 전환 비용 때문에 시스템 콜이 잦으면 전체가 느려진다. 시험에서는 이중 모드의 목적과 시스템 콜의 다섯 범주, 인터럽트의 종류가 단골 출제되고, 실무에서는 strace나 프로파일러로 불필요한 시스템 콜을 찾아 줄이는 것이 체감 성능을 좌우한다. 솔직히 이 주제를 공부하기 전과 후의 가장 큰 차이는, 내 코드 한 줄 아래에서 사용자 모드와 커널 모드가 끊임없이 교대하고 있다는 그림이 머릿속에 생겼다는 점이다.


메타 디스크립션: 사용자 프로그램이 하드웨어를 직접 못 건드리는 이유부터, 사용자 모드와 커널 모드를 가르는 이중 모드, 시스템 콜이 트랩을 통해 커널로 진입하는 과정, 그리고 이를 떠받치는 인터럽트 메커니즘과 성능 영향까지 운영체제 입문자 관점에서 세심하게 정리합니다.


소개 및 문의 · 개인정보처리방침 · 면책조항

© 2026 블로그 이름