테마
운영체제의 큰 그림 2
운영체제의 큰 그림에서 본 사용자 모드(user mode)와 커널 모드(kernel mode) 사이를 프로그램과 장치가 실제로 어떻게 오가는지 이어서 다룬다. 프로그램은 정해진 창구로 커널(kernel)에 일을 부탁하고, 장치와 명령어는 신호를 보내 커널을 깨운다. 끝으로 커널에 기능을 얼마나 넣느냐에 따라 나뉘는 두 가지 구조를 비교한다.
시스템 콜
사용자 모드의 프로그램이 파일을 읽거나 새 프로세스(process)를 만들려면 커널에 요청해야 한다. 그 공식 창구가 시스템 콜(system call)이다. 파일을 열고 읽고 쓰는 open·read·write, 프로세스를 복제하는 fork, 새 프로그램을 싣는 exec, 파일 내용을 메모리 주소에 연결하거나 새 메모리 영역을 받는 mmap이 대표적인 시스템 콜이다.
다이어그램 로딩…
- 프로그램은 보통 시스템 콜을 직접 부르지 않고, C 표준 라이브러리(glibc 등)의 같은 이름 함수를 부른다. 이 함수를 래퍼(wrapper)라고 한다.
- 래퍼는 어떤 시스템 콜인지 나타내는 번호와 인자를 레지스터(register)에 넣고 트랩(trap) 명령어1를 실행한다. 트랩은 프로그램이 일부러 커널로 들어가기 위해 실행하는 특별한 명령어다.
- CPU는 커널 모드로 바꾸고, 부팅 때 커널이 등록해 둔 처리 코드로 점프한다. 그래서 프로그램은 커널 안의 아무 주소로나 뛰어들 수 없고 커널이 정해 둔 입구로만 들어온다. 덕분에 잘못되거나 악의적인 코드도 인자 검사를 건너뛰고 커널 기능을 직접 실행하지 못한다.
- 커널은 인자가 올바른지 검사하고 일을 처리한 뒤, 결과를 담아 사용자 모드로 돌아간다.
라이브러리 함수가 모두 시스템 콜은 아니다. strlen처럼 계산만 하는 함수는 커널에 들어가지 않는다. printf는 문자열을 라이브러리 안에서 잠시 모아 두는 메모리 공간인 버퍼(buffer)에 모았다가 필요할 때 write 시스템 콜을 부른다. 시스템 콜을 부를 때마다 CPU는 레지스터 상태를 저장하고 권한 단계를 바꾸며, 커널은 인자를 검사한다. 이 비용이 일반 함수 호출보다 훨씬 크기 때문에, 이렇게 모아서 한 번에 부르는 방식이 흔하다.
인터럽트와 예외: 커널로 들어가는 길
CPU가 사용자 코드를 실행하다가 커널로 넘어가는 계기는 크게 세 가지다.
| 계기 | 누가 일으키나 | 예 |
|---|---|---|
| 하드웨어 인터럽트(interrupt) | 장치(아무 때나) | 디스크 읽기 완료, 네트워크 데이터 도착 |
| 예외(exception) | 실행 중인 명령어 | 0으로 나누기, 페이지 폴트(page fault) |
| 트랩 | 프로그램이 일부러 | 시스템 콜 |
하드웨어 인터럽트는 지금 실행 중인 명령어와 상관없이 장치가 아무 때나 일으킨다(비동기). 예외와 트랩은 특정 명령어를 실행한 결과로 생기므로, 같은 조건이면 같은 자리에서 다시 일어난다(동기). 부르는 이름은 자료마다 조금씩 다르다(자세한 분류는 CPU의 동작 2). 핵심은 어느 경우든 CPU가 커널 모드로 바뀌고 커널이 미리 정해 둔 처리 코드가 실행된다는 점이다. 특히 타이머 인터럽트가 중요하다. 타이머가 일정 간격으로 인터럽트를 걸기 때문에, 프로그램이 무한 루프에 빠져도 커널이 CPU를 되찾아 다른 프로세스에 타임 슬라이스(time slice)를 줄 수 있다.
커널 구조: 모놀리식과 마이크로커널
커널에 기능을 얼마나 넣느냐에 따라 구조가 나뉜다. 모놀리식 커널(monolithic kernel)은 커널 기능을 하나의 큰 프로그램에 담아 모두 커널 모드에서 실행한다. 마이크로커널(microkernel)은 커널을 최소한으로 줄이고, 파일 시스템(file system)이나 장치 드라이버(device driver)를 사용자 모드 프로세스로 내보낸다. 이렇게 내보낸 기능을 맡아 다른 프로세스의 요청을 받아 처리하는 프로세스를 마이크로커널에서는 서버라고 부른다.
| 기준 | 모놀리식 커널 | 마이크로커널 |
|---|---|---|
| 커널 안에 두는 것 | 파일 시스템·네트워크·드라이버까지 대부분 | 스케줄링(scheduling)·기본 메모리 관리·통신 정도만 |
| 나머지 기능 | 커널 안에서 함수 호출로 처리 | 사용자 모드의 별도 서버 프로세스 |
| 장점 | 구성 요소끼리 호출이 빨라 성능이 좋다 | 드라이버가 죽어도 커널은 산다 |
| 단점 | 드라이버 버그 하나가 커널 전체를 멈출 수 있다 | 서버끼리 메시지를 주고받는 비용이 든다 |
| 예 | 리눅스 | MINIX 3, QNX, seL4 |
리눅스는 모놀리식이지만 실행 중에 기능을 붙였다 뗄 수 있는 커널 모듈(kernel module)을 지원한다. Windows와 macOS의 커널은 하이브리드 커널(hybrid kernel)로 분류되곤 한다. 마이크로커널처럼 구성 요소를 나눠 설계했지만, 성능을 위해 파일 시스템과 드라이버 대부분을 커널 모드에서 실행한다는 뜻이다.
면접 포인트
- "시스템 콜이 뭔가요?" → 사용자 모드 프로그램이 커널 기능을 요청하는 유일한 창구. 트랩으로 커널 모드 전환 → 커널이 인자 검사·처리 → 복귀.
- "
printf는 시스템 콜인가요?" → 아니다. 라이브러리 함수이고, 내부에서 필요할 때write를 부른다. - 인터럽트(장치, 비동기)와 예외(명령어 때문, 동기)를 구분해 말하면 좋다. 타이머 인터럽트 덕분에 커널이 CPU를 강제로 되찾을 수 있다.
- "모놀리식 커널과 마이크로커널의 차이는?" → 기능을 커널 안에 모아 빠르게 호출하느냐, 커널 밖 사용자 모드 서버로 내보내 격리하느냐. 리눅스는 모놀리식에 커널 모듈을 더했다.
참고
