Back to Blog
운영체제시스템 콜커널모놀리식마이크로커널가상 머신프로세스 제어

0x02. 운영체제의 구조

운영체제가 제공하는 서비스, 시스템 콜의 동작 원리, 다양한 커널 구조(모놀리식, 계층형, 마이크로커널, 모듈), 그리고 가상 머신의 개념을 정리한다.

운영체제가 제공하는 서비스

운영체제 서비스 개요

운영체제(OS)는 사용자와 하드웨어 사이에서 다양한 서비스를 제공한다. 사용자가 컴퓨터를 편리하게 사용할 수 있도록 인터페이스를 제공하고, 프로그래머가 시스템 자원을 활용할 수 있도록 프로그래밍 인터페이스도 제공한다.

이 글에서는 운영체제의 서비스 구조, 시스템 콜의 동작 방식, 커널의 다양한 설계 방식, 그리고 가상 머신의 개념까지 살펴본다.


사용자 인터페이스

운영체제는 사용자와 소통하기 위해 크게 두 가지 인터페이스를 제공한다.

CLI (Command-Line Interpreter)

사용자가 명령어를 직접 입력하여 실행하는 방식이다. UNIX의 Shell이나 MS-DOS의 Command Prompt가 대표적이다.

GUI (Graphical User Interface)

마우스 기반의 윈도우-메뉴 시스템으로, 데스크톱 메타포(아이콘, 폴더 등)를 통해 시스템을 조작한다. 1973년 Xerox Alto에서 처음 등장했고, 1980년대 Apple Macintosh를 거쳐 MS-Windows, X-window 기반 데스크톱(CDE, KDE, GNOME)까지 발전해왔다.


프로그래밍 인터페이스

운영체제는 프로그램이 하드웨어 자원을 활용할 수 있도록 시스템 콜(System Call) 이라는 프로그래밍 인터페이스를 제공한다. 시스템 콜은 소프트웨어 인터럽트(S/W Interrupt)의 한 종류다.

POSIX I/O 시스템 콜 예시 (unistd.h에 선언):

int open(const char *pathname, int flags, mode_t mode);
int close(int fd);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
// size_t: unsigned int, ssize_t: signed int

open() 같은 시스템 콜을 이용해서 C 표준 라이브러리의 fopen()이 구현된다. C 언어 자체에는 없는 OS 고급 기능이 UNIX 시스템 콜에는 존재한다.


시스템 콜의 동작 원리

시스템 콜(System Call) 은 애플리케이션이 OS 커널에 서비스를 요청하는 메커니즘이다. 핵심 특징은 다음과 같다.

  • 인터럽트를 통해 커널 함수를 호출하며, user mode에서 kernel mode로 전환된다
  • 일반적으로 C/C++ 또는 어셈블리로 작성된 인터럽트 핸들러(Interrupt Handler) 형태로 제공된다
  • 낮은 권한 모드에서 높은 권한 모드로 안전하게 제어를 이전하는 메커니즘이다

대표적인 POSIX 시스템 콜: open, close, read, write, fork, kill, wait

시스템 콜 처리 흐름

인터럽트 핸들러와 시스템 콜 핸들러는 약간 다르다. 인터럽트 핸들러가 처리할 때 시스템 콜 핸들러를 호출하는 구조다.


시스템 콜의 매개변수 전달

시스템 콜은 내부적으로 인터럽트를 통해 처리되며, 추가 정보가 필요한 경우 매개변수 전달(Parameter Passing) 방법이 사용된다.

방법설명
레지스터정보의 양이 작을 때 사용
블록 주소정보의 양이 클 때, 메모리 블록의 주소를 레지스터에 저장
시스템 스택스택에 매개변수를 push/pop

매개변수 전달 방식

시스템 콜의 유형

시스템 콜은 기능에 따라 다섯 가지로 분류된다.

  • 프로세스 제어 (Process Control)
  • 파일 관리 (File Management)
  • 장치 관리 (Device Management)
  • 정보 유지 (Information Maintenance)
  • 통신 (Communication)

시스템 콜 유형 예시


시스템 콜 인터페이스

고급 언어에서 시스템 콜을 어떻게 호출할까? 예를 들어 int open(const char *path, int oflag); 같은 함수를 호출하면, 내부적으로 어떤 일이 일어나는 것일까?

시스템 콜 인터페이스(System-Call Interface) 는 프로그래밍 언어의 런타임 지원 시스템과 OS 시스템 콜 사이의 연결 고리다. glibc(Linux)나 MS libc(Windows)가 이 역할을 담당한다.

시스템 콜 인터페이스 구조

Linux에서의 시스템 콜 인터페이스 예시

일반적으로 각 시스템 콜에는 번호가 부여된다. 시스템 콜의 IRQ 번호는 Linux에서 0x80, DOS/Windows에서 0x21이다. 시스템 콜 인터페이스는 이 번호로 인덱싱된 테이블을 유지한다.

시스템 콜 인터페이스는 OS 커널에서 의도된 시스템 콜을 호출하고, 그 상태와 반환값을 돌려준다. 호출자는 시스템 콜이 어떻게 구현되었는지 알 필요가 없다. API를 준수하고 OS가 무엇을 해줄지만 이해하면 된다. 대부분의 OS 인터페이스 세부사항은 API 뒤에 숨겨져 있으며, 런타임 지원 라이브러리(Run-time Support Library) 가 관리한다.

시스템 콜 인터페이스가 하는 일:

  • 커널에 정보를 전달
  • 커널 모드로 전환
  • 커널 모드 실행을 위한 데이터 처리 및 준비

시스템 콜 vs. 프로그래밍 언어의 I/O 함수:

  • read(): OS가 제공하는 시스템 콜
  • fread(): C 언어에서 정의된 표준 함수 (호환성을 위해 존재)
  • fread()는 내부적으로 read()를 사용하여 구현된다

시스템 콜 예시들


API (Application Programming Interface)

API는 컴퓨터 시스템(OS), 라이브러리, 애플리케이션이 서비스 요청을 허용하기 위해 제공하는 인터페이스다. 시스템 콜보다 좀 더 큰 단위의 함수로 구성된다.

  • 애플리케이션 프로그래머가 사용할 수 있는 함수, 매개변수, 반환값의 집합이다
    • 예: Win32 API, POSIX API 등 (MessageBox(..), CreateWindow(..) 등)
  • 시스템 콜과 밀접한 관계를 가질 수 있다
    • 예: POSIX API는 UNIX 시스템 콜과 거의 동일
  • 시스템 콜을 기반으로 더 고수준의 기능을 제공하기도 한다
    • 예: Win32 API, POSIX 스레드 라이브러리 API

API와 시스템 콜의 관계

Windows OS에서는 API가 호환성을 크게 높여주지만, Linux에서는 시스템 콜과 API의 차이가 비교적 작다.


프로세스 제어

프로세스의 적재와 실행

하나의 프로그램이 다른 프로그램을 적재(load)하고 실행(execute) 할 수 있다. CLI, Windows 탐색기, macOS Finder가 대표적인 예다.

이때 부모 프로그램은 다음 중 하나의 상태를 가진다.

  • 자식 프로그램에 의해 교체됨 (lost)
  • 일시 중지됨 (paused)
  • 계속 실행됨: 멀티프로그래밍 / 멀티태스킹
    • 새 프로세스를 생성하거나 작업을 제출

FreeBSD UNIX 예시

FreeBSD UNIX 프로세스 제어

커맨드 인터프리터는 새 프로그램을 실행한 뒤에도 계속 실행될 수 있다. 부모의 실행에는 두 가지 경우가 있다.

Case 1: 계속 실행

새 프로그램이 백그라운드에서 실행된다. 이 경우 콘솔 입력이 불가능하다.

Case 2: 자식 프로세스를 기다림 (wait())

새 프로세스가 I/O를 접근하며, 종료(exit()) 시 상태 코드(0 또는 에러 코드)와 함께 부모(예: 셸)에게 제어권이 돌아간다.

핵심 시스템 콜:

  • fork(): 반환값이 0이면 자식, 0보다 크면 부모, 0보다 작으면 에러
  • exec() 계열 함수
    • execlp: 예) execlp("ls", "ls", "-al", "/tmp", NULL);
    • execvp: 예) execvp(argv[0], argv);
  • wait(): 자식 종료 시까지 대기. 반환값이 0보다 작으면 에러

프로세스 제어 기능:

  • 프로세스 속성 조회/설정 (우선순위, 최대 실행 시간 등)
  • 프로세스 종료 (다른 사용자의 프로세스는 종료할 수 없다)
  • 일정 시간 대기 또는 이벤트/시그널(타이머, 마우스 등) 대기

프로세스 제어 시스템 콜

디버깅:

  • Dump: 메모리 상태 저장
  • Trace: 매 명령어 실행 후 트랩

디버깅 시스템 콜


프로세스 종료

프로세스 종료에는 두 가지 방식이 있다.

정상 종료: exit()

프로세스의 자원을 해제하고, 현재 프로세스에 대한 정보를 정리한다.

비정상 종료: abort()

디버깅과 분석을 위해 메모리를 파일에 덤프(Dump) 한다. 메모리 덤프란 컴퓨터 메모리의 내용을 파일로 저장하는 것으로, 프로그램 크래시 등의 원인을 파악하는 데 사용된다. 덤프 파일은 텍스트가 아닌 이진 파일로 저장되며, 전용 도구를 통해 분석한다. 잘못된 메모리 주소 접근 같은 경우에는 사용자에게 처리 방법을 물을 수도 있다.


파일 관리

파일 관리 시스템 콜

운영체제의 파일 관리 기능은 다음을 포함한다.

  • 파일 생성 / 삭제
  • 읽기 / 쓰기 / 위치 변경(reposition)
  • 파일 속성 조회 / 설정
  • 디렉토리 연산
  • 이동(move), 복사(copy) 등의 추가 서비스

이러한 기능은 시스템 콜, API, 또는 독립적인 시스템 프로그램 중 하나의 형태로 제공된다.


장치 관리

운영체제에서 장치는 물리 장치(디스크, 테이프 등)와 추상/가상 장치(파일 등)로 나뉜다.

장치에 대한 기본 연산은 파일 연산과 비슷하다.

연산시스템 콜
독점 사용 요청open()
읽기, 쓰기, 위치 변경read(), write()
사용 해제close()

운영체제는 파일과 장치를 통합된 구조로 관리한다. I/O를 특수 파일에 매핑하여 파일과 장치 모두에 동일한 시스템 콜을 사용한다. 장치마다 다양한 버전이 필요한 부분은 디바이스 드라이버(Device Driver) 가 제공한다.

장치와 파일의 통합 구조


정보 유지 (Information Maintenance)

운영체제와 사용자 프로그램 사이에서 다양한 정보를 전달하는 기능이다.

  • 현재 시간, 날짜
  • 시스템 정보: 현재 사용자 수, OS 버전, 남은 메모리/디스크 공간

OS는 모든 프로세스에 대한 정보를 관리한다. Linux의 /proc 파일시스템이 대표적인 예로, CPU 정보나 메모리 상태 같은 커널 내부 데이터(변수)를 파일처럼 접근할 수 있다.


시스템 프로그램

시스템 프로그램(System Program) 은 프로그램 개발과 실행을 위한 편리한 환경을 제공하는 프로그램이다. user mode에서만 동작하며, 사실상 사용자 애플리케이션이다. 셸, 윈도우 탐색기, 맥 Finder가 대표적이다.

시스템 프로그램의 분류


운영체제의 구조

범용 운영체제는 매우 큰 프로그램이다. 이를 어떻게 구조화하느냐에 따라 성능, 안정성, 확장성이 크게 달라진다. 대표적인 구조 방식은 다음과 같다.

  • 모놀리식(Monolithic): MS-DOS, 초기 UNIX, Linux
  • 계층형(Layered): 추상화 계층 기반
  • 마이크로커널(Microkernel): Mach

단순 구조 (Simple Structure)

MS-DOS 구조

MS-DOS (1981) 는 단일 사용자, 단일 작업 환경을 위해 설계되었다. 최소한의 공간으로 최대한의 기능을 제공하는 것이 목표였다.

하지만 인터페이스와 기능 수준이 잘 분리되지 않았으며, 다음과 같은 한계가 있었다.

  • 하는 일이 많지 않아 이중 모드(Dual Mode) 나 하드웨어 보호가 없음
  • 애플리케이션이 I/O에 직접 접근 가능
  • 잘못된 프로그램에 취약: 하나의 프로그램 오류가 전체 시스템을 다운시킬 수 있음
  • 특정 하드웨어에 종속적

모놀리식 구조 (Monolithic Structure)

모놀리식 커널 구조

모놀리식 커널(Monolithic Kernel) 은 시스템 콜 인터페이스 아래, 물리 하드웨어 위에 있는 모든 것을 하나의 커널에 포함하는 구조다. 파일 시스템, CPU 스케줄링, 메모리 관리 등 모든 기능이 하나의 레벨에 집중된다.

가장 큰 장점은 빠르다는 것이다. 모든 기능이 같은 주소 공간에서 실행되기 때문이다.

  • 초기 UNIX (1973): 하드웨어 기능에 제한되었고, 시스템 프로그램으로 셸, 컴파일러, 인터프리터, 시스템 라이브러리 등을 제공
  • Linux (1991): 모놀리식 구조를 기반으로 발전

계층형 접근 (Layered Approach)

계층형 구조

운영체제를 여러 계층(Layer) 으로 구성하는 방식이다. 각 계층은 추상 객체와 연산을 구현하며, 하위 계층의 함수/서비스만을 사용한다. 상위 계층은 하위 계층을 호출하고, 하위 계층은 상위 계층에 의해 호출된다.

장점: 개발과 디버깅이 단순하다

계층형 장점

하위 계층부터 상위 계층으로 개발하면, 각 단계에서 현재 계층에만 집중할 수 있다. 하위 계층의 세부 구현을 알 필요가 없다.

어려움:

계층 정의의 어려움

다양한 계층을 정의하려면 신중한 설계가 필요하다. 서로를 필요로 하는 모듈 간의 계층 관계를 정의하기 어렵다.

모듈 간 상호 의존성

또한 비효율성 문제가 있다. 하위 계층으로의 반복 호출이 오버헤드를 만든다.

반복 호출 오버헤드

해결책: 계층 수를 줄여서 장점은 취하고 단점은 피한다.


마이크로커널 (Microkernel)

마이크로커널 구조

마이크로커널은 커널을 최대한 작게 만드는 접근 방식이다. 불필수적인 구성 요소는 커널에 구현하지 않고, 시스템/사용자 수준의 프로그램으로 분리한다. 일반적으로 프로세스 관리, 메모리 관리, 통신 기능만 커널에 포함된다.

시스템 콜은 메시지 패싱(Message Passing) 을 통해 제공된다. 클라이언트와 서비스는 사용자 공간에서 실행되고, 커널은 클라이언트와 서버 사이의 메시지 전달 기능만 제공한다.

장점: 커널의 양이 작아서 문제가 발생할 확률이 낮다 (안전성이 높다)

  • 확장 용이: 새로운 서비스를 추가하기 쉽다
  • 이식 용이: 다른 하드웨어로 포팅하기 쉽다
  • 보안과 신뢰성: 대부분의 서비스가 사용자 공간에서 실행된다

단점:

  • 시스템 기능 오버헤드 증가로 인한 성능 저하

커널 모듈 (Loadable Kernel Modules)

커널 모듈 구조

적재 가능 커널 모듈(LKM, Loadable Kernel Modules) 은 객체 지향적 접근 방식을 사용한다. 각 핵심 구성 요소가 분리되어 있고, 잘 정의된 인터페이스를 통해 서로 통신한다. 필요에 따라 커널 안에 동적으로 적재/제거할 수 있다. Linux, Solaris 등에서 사용된다.

사용하는 모듈만 끼웠다 뺐다 할 수 있어서 매우 유연(flexible) 하며, 실행 중에도 빠르게 대응할 수 있다.

장점:

  • 핵심 서비스를 제공하면서, 특정 기능을 동적으로 구현 가능

계층형 구조와의 비교:

  • 유연하다. 어떤 모듈이든 다른 어떤 모듈을 호출할 수 있다

마이크로커널과의 비교:

커널 모듈 vs 마이크로커널

  • 각 모듈이 커널 모드에서 실행된다
  • 메시지 패싱을 호출할 필요가 없어 빠르다
  • 다만 커널 모드에서 실행되므로, 모듈에 문제가 생기면 시스템 전체가 영향을 받을 수 있다 (약간의 위험성)

하이브리드 시스템 (Hybrid Systems)

대부분의 현대 운영체제는 하나의 순수 모델이 아니다. 하이브리드 방식은 여러 접근법을 결합하여 성능, 보안, 유용성을 모두 충족시킨다.

  • Linux, Solaris: 커널 주소 공간 안에 모놀리식 구조를 사용하면서, 기능의 동적 로딩을 위해 모듈 방식을 결합
  • Windows: 대부분 모놀리식이지만, 서브시스템 지원을 위해 마이크로커널 개념을 결합
  • Apple macOS X: 계층형 구조 + Aqua UI + Cocoa 프로그래밍 환경. 커널은 Mach 마이크로커널과 BSD UNIX로 구성되며, I/O Kit과 동적 적재 모듈(커널 익스텐션)을 포함

macOS와 iOS

macOS/iOS 구조

Apple 운영체제는 네 개의 계층으로 구성된다.

User Experience 계층

사용자가 컴퓨팅 장치와 상호작용하는 소프트웨어 인터페이스를 정의한다. macOS는 Aqua UI, iOS는 Springboard UI를 사용한다.

Application Frameworks 계층

Objective-CSwift 프로그래밍 언어를 위한 API를 제공한다. macOS는 Cocoa, iOS는 Cocoa Touch 프레임워크를 사용한다.

Core Frameworks

그래픽과 미디어를 지원하는 프레임워크를 정의한다. QuickTime, OpenGL 등이 포함된다.

Kernel Environment (Darwin): 하이브리드 구조

주로 Mach 마이크로커널BSD UNIX 커널로 구성된 계층형 시스템이다.

Darwin 커널 구조


Android

Android 구조

Android는 Linux 커널 위에 구축된 모바일 운영체제로, 다음과 같은 구성 요소를 가진다.

  • ART (Android Run-Time): AOT(Ahead-of-Time) 컴파일을 지원하는 런타임
  • JNI (Java Native Interface): Java와 네이티브 코드 간의 인터페이스
  • Native Libraries: 네이티브 라이브러리
  • HAL (H/W Abstraction Layer): 특정 하드웨어에 독립적인 일관된 뷰를 제공
  • Bionic: Android용 표준 C 라이브러리 (glibc의 Android 버전)

가상 머신 (Virtual Machines)

가상 머신(Virtual Machine) 은 컴퓨터 플랫폼과 운영체제 사이에 가상화된 환경을 만드는 소프트웨어다. 사용자는 추상적인 머신 위에서 소프트웨어를 운영할 수 있다.

하나의 컴퓨터 하드웨어를 여러 개의 서로 다른 실행 환경으로 추상화하며, 각 실행 환경은 호스트 컴퓨터를 정확히 에뮬레이트한다.

가상 머신 개념


구현의 문제

가상 머신을 구현하기 위해서는 기반 머신을 정확히 복제해야 하므로 많은 작업이 필요하다. 이중 모드 연산을 지원하기 위해 가상 이중 모드(Virtual Dual Mode) 를 사용한다.

  • VM 소프트웨어 자체는 커널 모드에서 실행될 수 있지만, VM 위의 OS는 사용자 모드에서 실행된다
  • 가상 사용자 모드 / 가상 커널 모드가 존재한다
  • 가상 사용자 모드에서의 시스템 콜은 VM 모니터가 시뮬레이션한다
  • 많은 CPU가 2개 이상의 특권 수준을 지원한다

가상 머신의 이중 모드


가상 머신의 자원 관리

각 프로세스는 자신만의 CPU와 메모리를 가진 것처럼 보인다. 이는 CPU 스케줄링가상 메모리 기술로 구현된다. 가상 메모리는 소프트웨어가 실제 물리 메모리와 반드시 연결되지 않은 메모리 주소 공간에서 실행될 수 있게 해준다.

가장 큰 어려움은 디스크 공간이다. 모든 가상 머신에 동일한 디스크 드라이브를 할당하는 것은 불가능하므로, 가상 디스크(Minidisks) 를 사용한다. 가상 디스크는 크기를 제외하면 모든 면에서 실제 디스크와 동일하다.


가상 머신의 장점

  • 시스템 자원의 완전한 보호: 각 VM은 외부와 격리되어 있다
    • VM 간 공유가 필요한 경우: 공유 미니디스크, 가상 네트워크 연결
  • OS 연구, 개발, 교육에 완벽한 도구: OS를 변경하는 것은 위험한 작업이다. VM에서 작업하면 물리 머신을 중단할 필요가 없다

가상 머신의 한계

호스트 시스템과의 불가피한 차이가 존재한다.

  • 디스크 크기: 실제보다 작은 가상 디스크를 사용
  • 실행 시간:
    • 많은 VM 간의 멀티프로그래밍이 예측 불가능한 방식으로 VM을 느리게 만들 수 있다
    • 특권 명령어(Privileged Instructions) 는 시뮬레이션되므로 느리다
    • 가상 I/O는 스풀링(spooling)으로 더 빠를 수도 있고, 해석(interpreted)으로 더 느릴 수도 있다

HGU 전산전자공학부 김인중 교수님의 23-1 운영체제 수업을 듣고 작성한 포스트이며, 첨부한 모든 사진은 교수님 수업 PPT의 사진 원본에 필기를 한 수정본입니다.