Search

Chapter 2. 운영체제 구조

생성일
2023/06/06 05:47
태그

운영체제 서비스

운영체제는 프로그램과 프로그램 사용자에게 특정 서비스를 제공한다.
1.
사용자 인터페이스(user interface)
거의 모든 운영체제는 사용자 인터페이스(UI)를 제공하며, 가장 일반적으로 그래픽 사용자 인터페이스(GUI)가 있다. 윈도우의 커서나 메뉴, 아이콘 등이 GUI에 해당되고, 키보드와 마우스도 사용자 인터페이스에 포함된다.
사용자 인터페이스의 또 다른 옵션은 키보드로 명령어를 입력받아 동작을 수행하는 명령어 라인 인터페이스(CLI)이다.
2.
프로그램 수행(program execution)
시스템은 프로그램을 메모리에 로드하여 프로세스를 실행시키며, 정상적으로든 비정상적으로든 프로세스를 끝낼 수 있어야 한다.
3.
입출력 연산(I/O operation)
효율과 보호를 위해 사용자들은 통상 입출력 장치를 직접 제어할 수 없는데, 파일이나 입출력 장치에 대해서 입출력을 요청받으면 운영체제가 입출력을 수행하기 위한 방법을 제공해야 한다.
4.
파일 시스템 조작(file system manipulation)
프로그램은 파일을 읽거나 쓸 필요가 있는데, 프로그램이 이름을 가지고 파일을 생성하거나 검색, 삭제할 수 있어야 한다.
일부 프로그램은 파일 권한을 통해 파일이나 디렉토리의 접근을 허가하거나 거부할 수 있어야 한다. 많은 운영체제들이 특성과 성능에 맞춰 다양한 파일 시스템을 제공한다.
5.
통신(communication)
하나의 컴퓨터 내에서 프로세스들 사이에 통신을 하거나, 네트워크에 묶여있는 서로 다른 컴퓨터 상의 프로세스 사이에 데이터를 송수신할 수 있어야 한다.
통신은 공유 메모리를 통해 구현되거나, 정보 패킷을 통해 프로세스 사이에 데이터를 전달하는 메세지 전달(message passing) 방식이 사용되어 구현될 수 있다.
6.
오류탐지(error detection)
운영체제는 가능한 모든 오류에 대해 인지하고 있어야 한다.
오류는 CPU나 메모리 하드웨어, 입출력 장치, 사용자 프로그램 등에서 일어날 수 있는데, 운영체제는 각 유형의 오류에 대해 적당한 조치를 취하여 올바르고 일관성 있는 계산을 보장해야한다.
운영체제는 사용자에게 서비스를 제공하는게 목적이 아닌, 시스템의 효율적인 동작을 보장하기 위한 서비스도 제공한다.
1.
자원 할당(resource allocation)
다수의 프로세스나 다수의 작업이 동시에 실행될 때, 그에 맞춰 각각 자원을 할당해 주어야 한다.
2.
기록작성(logging)
어떤 프로그램이 어떤 자원을 어떻게 사용하는지를 추적하기 위해서나 통계를 위해 기록을 관리할 수 있어야 한다.
3.
보호(protection)와 보안(security)
운영체제에는 시스템 자원에 대한 접근이 통제되기 위한 보호 기능과, 외부로부터의 시스템 보안이 필요하다.

사용자와 운영체제 인터페이스

1.
명령어 인터프리터
Linux나 UNIX, Windows를 포함한 대부분 운영체제는 명령 인터프리터를 통해 프로세스가 시작되거나 첫 로그인할 때 수행되는 특수 프로그램으로 취급한다.
명령 인터프리터를 제공하는 시스템에서 이 명령 인터프리터는 쉘(shell)이라 불린다.
명령 인터프리터의 주요 기능은 사용자가 입력한 명령을 찾고 해당 명령을 수행하는 것이다. 이를 통해 파일의 생성, 삭제, 파일 리스트, 프린트, 복사 등을 수행할 수 있다.
명령 인터프리터에서의 명령어는 인터 프리터 자체에 명령어에 대한 실행할 코드를 가지고 있는 것과, 시스템 프로그램으로 명령을 구현하는 방법이 있다.
2.
그래픽 사용자 인터페이스
그래픽 사용자 인터페이스는 Windows 운영체제에서 마우스를 기반으로하여 윈도우 메뉴 시스템을 사용하는 것처럼, 사용자 인터페이스를 그래픽을 통해서 제공하는 방법이다.
Windows 운영체제를 예시로 들면, 사용자는 마우스를 움직여 마우스 포인터로 프로그램의 아이콘을 통해서 프로그램을 실행시키거나 이동, 삭제 등의 기능을 수행할 수 있다.
3.
터치스크린 인터페이스
터치스크린 인터페이스는 사용자가 터치스크린을 통해 아이콘을 누르거나 스와이프하는 등의 제스처를 통해 상호작용하는 방법이다.
초기 휴대폰에는 자판이 존재했었지만, 최근의 대부분 모바일 시스템에는 명령 라인 인터페이스나 마우스, 키보드 시스템을 적용하기에 부적합하기 때문에, 일반적으로 $터치스크린 인터페이스를 사용한다.
4.
인터페이스 선택
컴퓨터 시스템에서 어떤 인터페이스를 선택하는 지는 개인의 선호에 달려있다. 컴퓨터를 관리하는 시스템 관리자와 시스템을 잘 알고 있는 파워 유저들은 명령 라인 인터페이스를 사용하는게 더 효율적이고, 그렇지 않다면 GUI가 더 효율적일 수 있다.

시스템 콜

1.
시스템 콜
시스템 콜(System call)은 운영체제의 커널에게 제공되는 프로그래밍 인터페이스로, 응용 프로그램은 시스템 콜을 사용해 운영체제의 기능과 서비스에 접근할 수 있다.
파일 및 디렉토리 생성, 삭제, 읽기, 쓰기, 탐색과 같은 파일 시스템 관리 기능과 프로세스 생성, 종료, 상태 조회, 프로세스 간 통신 같은 프로세스 관리 기능, 메모리 할당, 해제, 보호 등 메모리 관리 기능, 키보드, 마우스, 디스플레이 등 입출력 관리 기능, 네트워크 연결, 소켓 생성, 데이터 전송 등의 네트워크 관리 기능이 시스템 콜에 해당한다.
응용 프로그램은 open(), read(), write(), fork(), exec()와 같은 C나 C++에서 제공하는 라이브러리 함수를 사용하여 시스템 콜을 호출한다
2.
응용 프로그래밍 인터페이스(API)
위와 같이 간단한 프로그램이라도 시스템 콜을 많이 사용하지만, 프로그램을 만들 때 이런 많은 시스템 콜을 전부 알 필요가 없다. 그 이유는 응용 프로그래밍 인터페이스(API, Application programming Interface)에 따라 프로그램을 설계하기 때문이다.
API는 각 함수에 전달되어야 할 매개변수들과 프로그래머가 기대할 수 있는 반환 값을 포함한 함수의 집합으로 사용된다. open(), read(), write(), fork(), exec()의 함수들이 그 예로, UNIX와 Linux 시스템에서 C언어로 작성된 프로그램을 위해 제공되는 라이브러리는 libc로 불린다.
API를 구성하는 함수들은 프로그래머를 대신해서 시스템 콜을 호출한다. 예시를 들면, Windows 함수인 CreateProcess() 함수는 실제로 Windows 커널의 NTCreateProcess() 시스템 콜을 호출한다.
시스템 콜은 프로그램 상에서 작업하기가 쉽지않은데다가, API를 통해 프로그래밍을 하면 같은 API를 지원하는 어느 시스템에서나 컴파일되고 실행되는 것을 보장할 수 있기 때문에 실제 시스템 콜을 부르지 않고 API를 통해 프로그래밍을 하는 것이다.
실행시간 환경(RTE, Runtime Environment)은 운영체제가 제공하는 시스템 콜에 대한 연결고리 역할을 하는 시스템 콜 인터페이스를 제공한다. 시스템 콜 인터페이스는 테이블을 만들어 시스템 콜에 할당된 번호를 찾고 시스템 콜을 호출한다.
결과적으로 API에 의해 시스템 콜에 대한 자세한 내용은 프로그래머가 알 필요가 없고, API는 시스템 콜 인터페이스(RTE)에 의해 관리된다.
3.
시스템 콜의 유형
프로세스 제어
파일 조작
장치 조작
정보 유지보수
통신
보호

시스템 서비스

시스템 서비스(System Service)는 응용 프로그램이 운영체제의 기능과 서비스를 활용할 수 있도록 제공되는 API로, 시스템 유틸리티(System utility)로도 불린다. 시스템 서비스는 운영체제와 응용 프로그램이 상호작용하기 위해 호출할 수 있는 함수나 절차 형태로 제공된다.
파일 시스템 서비스
파일 및 디렉토리 생성, 읽기, 쓰기, 삭제 등 파일 시스템 관련 작업을 수행하는 서비스를 제공한다.
프로세스 관리 서비스
프로세스 생성, 종료, 프로세스 간 통신, 스케줄링 등 프로세스 관리 작업을 수행하는 서비스를 제공한다.
메모리 관리 서비스
메모리 할당, 해제, 가상 메모리 관리, 메모리 보호 등 메모리 관리 작업을 수행하는 서비스를 제공한다.
입출력 서비스
키보드, 마우스, 디스플레이, 프린터 등 입출력 장치와 상호작용하기 위한 서비스를 제공한다.
네트워크 서비스
네트워크 연결, 소켓 생성, 데이터 전송, 프로토콜 지원 등 네트워크 관련 작업을 수행하는 서비스를 제공한다.

링커와 로더

일반 적으로 프로그램은 디스크에 a.out이나 prog.exe와 같이 이진 실행 파일 형태로 존재하고, CPU에서 프로그램을 메모리로 가져와 프로세스 형태로 배치한다.
소스 파일은 임의의 물리 메모리 위치에 로드되도록 설계된 재배치 가능 오브젝트 파일로 컴파일되고, 링커는 이 재배치 가능 오브젝트 파일을 하나의 이진 실행 파일 형태로 결합한다. 로더는 이진 실행 파일을 메모리에 로드하여 CPU 코어에서 실행할 수 있는 상태로 만든다.
이런 링커와 로더에 관련된 일련의 과정은 재배치라 하며, 프로그램 부분에 최종 주소를 할당하고 프로그램 코드와 데이터를 해당 주소와 일치하도록 조정하여 프로그램이 실행될 때 코드가 라이브러리 함수를 호출하고 변수에 접근할 수 있게 한다.
대부분의 실제 시스템에서는 프로그램이 메모리에 로드될 때 라이브러리를 동적으로 링크할 수 있게 한다. Windows에서는 동적 링킹 라이브러리(DLL, Dynamically Liked Library)를 지원한다.
오브젝트 파일과 실행 파일은 일반적으로 표준화된 형식을 가지는데, UNIX 및 Linux 시스템에서는 이 표준 형식을 ELF(Excutalbe and Linkable Format)이라 부른다. 재배치 가능 파일과 실행 파일 각각을 위한 별도의 ELF 형식이 사용된다. Windows 시스템은 PE(Portable Executable), macOS는 Mach-O 형식을 사용한다.

응용 프로그램이 운영체제마다 다른 이유

기본적으로 하나의 운영체제에서 컴파일된 응용 프로그램은 다른 운영체제에서 실행할 수 없는데, 운영체제에서 제공하는 시스템 콜이 서로 다르기 때문이다.
동일한 응용 프로그램을 다른 운영체제에서 사용 가능한 경우는 3가지 방법이 있다.
1.
Python이나 Ruby와 같이 운영체제마다 지원하는 인터프리터 언어로 응용 프로그램을 작성하는 방법이 있다. 이는 기계어 코드로 구성된 응용 프로그램에 비해 성능이 떨어지고 응용 프로그램의 기능이 제한될 수 있다.
2.
응용 프로그램을 가상 머신을 포함하고 있는 언어로 작성하는 방법이 있다. Java는 로더, 바이트코드 검증기, Java 응용 프로그램을 Java 가상 머신으로 로드하는 구성요소들을 RTE로 가지고 있다. 이론적으로 모든 Java 앱은 RTE가 제공되는 환경이면 어디서나 실행될 수 있다. 이런 시스템은 인터프리터 시스템과 유사한 단점을 가진다.
3.
이식할 운영체제의 표준 언어와 API에 맞춰 운영체제마다 고유의 이진 실행 파일을 생성하는 방법이 있다. 이식에 걸리는 시간이 무척 길고 응용 프로그램의 새 버전마다 수많은 디버깅을 거쳐야 한다는 단점이 있다.

운영체제 구조

1.
모놀리식 구조
구조가 없는 형태의 운영체제로, 커널의 모든 기능을 단일 주소 공간에서 실행되는 단일 정적 이진 파일에 넣는 것이 모놀리식 구조이다.
최초의 UNIX 운영체제가 모놀리식 구조이며, 커널과 시스템 프로그램의 두 부분으로 구성된다.
Linux 운영체제는 아래와 유사하게 구성되는데, Linux 커널은 단일 주소 공간에서 커널 모드로 전부 실행된다는 점에서 모놀리식이지만, 런타임 중에 커널을 수정할 수 있는 모듈식 설계를 갖추고 있다.
모놀리식은 시스템 콜 인터페이스의 오버헤드가 거의 없고 커널 안에서 통신 속도가 빠르다는 장점이 있다.
시스템의 한 부분을 변경하면 다른 부분에 광범위한 영향을 줄 수 있기 때문에 밀접하게 결합된 시스템으로 불린다.
2.
계층적 접근
느슨하게 결합된 시스템은 특정 기능 및 한정된 기능을 작은 구성요소로 나누고, 모든 구성요소를 합쳐서 커널을 구성한다. 이렇게 구성하면 한 구성요소의 변경이 다른 구성요소에는 영향을 미치지 않으므로, 시스템 내부 동작을 더 자유롭게 생성하고 변경할 수 있다는 장점이 있다.
계층적 접근 방식은 느슨하게 결합된 시스템 중 하나로 운영체제를 여러 개의 층으로 나누는 방식이다.
운영체제 층은 하위층에 대한 연산을 호출할 수 있고, 자료구조와 상위층에서 호출할 수 있는 루틴의 집합으로 구성된다. 각 층은 자신보다 하위 수준의 층에 의해 제공된 연산만을 사용해 구현되고, 하위 층의 연산이 어떻게 구현되었는지 알 필요가 없다.
계층적 접근 방식은 구현과 디버깅이 간단하다는 장점이 있다. 각 층은 시스템의 다른 층을 신경쓰지 않고 구현과 디버깅을 할 수 있고, 이는 시스템의 설계나 구현이 간단해진다.
계층적 접근 방식은 컴퓨터 네트워크(TCP/IP) 및 웹 응용 프로그램에서 사용된다. 계층적 접근 방식은 각 계층의 기능을 적절하게 정의해야한다는 단점이 있고, 여러 계층을 통과함에 따라 발생하는 오버헤드로 성능이 저하된다.
3.
마이크로 커널
마이크로 커널 접근 방식은 모놀리식 구조에서 커널의 중요치 않은 구성요소를 커널에서 제거하고 별도의 주소 공간에 사용자 모드 프로그램으로 구현하는 방식이다.
마이크로 커널 접근 방식의 대표적인 예는 macOS 및 iOS 운영체제의 커널 구성요소인 Darwin이다. Darwin은 두 개의 커널로 구성되는데 그중 하나는 Mach 마이크로 커널 접근 방식이 사용되었다.
마이크로 커널 접근 방식의 장점은 하나의 하드웨어에서 다른 하드웨어로 이식이 쉽고 운영체제의 확장이 쉽다는 것이다. 또한 대부분의 서비스가 커널이 아니라 사용자 프로세스로 수행되기 때문에, 보안성과 신뢰성이 높다.
마이크로 커널은 두 개의 사용자 수준 서비스가 통신해야 하는 경우 별도의 주소 공간에 서비스가 존재하기 때문에 메세지가 복사되어야 하는 것 등, 가중된 시스템 기능 오버헤드로 인해 성능이 나빠진다.
4.
모듈
적재 가능 커널 모듈(LKM, Loadable Kernel Module) 방식은 커널이 핵심적인 구성요소들을 가지고 있고, 부팅 중이나 실행 중에 부사적인 서비스들을 모듀을 통해서 링크하는 방식이다.
Linux, Mac OS X, Solaris, Windows 등 최근의 UNIX 기반 운영체제에서 대부분 LKM 방식을 사용한다.
LKM은 커널이 핵심 서비스를 제공하고 다른 서비스들은 커널이 실행되는 동안 동적으로 링크한다. 서비스를 동적으로 링크하는 것은 수정 사항이 생길 때마다 커널을 다시 컴파일할 필요가 없기 때문에, 새로운 기능을 커널에 직접 추가하는 것 보다 바람직하다.
전체적인 구조는 계층 구조를 닮았지만, 모듈이 다른 모듈을 호출할 수 있다는 점에서 계층 구조보다 유연하다. 또한 중심 모듈이 핵심 기능만 가지고 다른 모듈을 로드한다는 점에서 마이크로 커널과 유사하지만, 모듈 간에 통신하기 위해 메시지 전달을 호출할 필요가 없기 때문에 더 효율적이다.
5.
하이브리드 시스템
Linux는 운영체제가 전부 하나의 주소 공간에 존재하기 때문에 모놀리식 구조지만 모듈을 사용하여 동적으로 커널에 추가할 수 있다. Windows도 마찬가지로 전체적으로는 모놀리식 구조를 채용하지만 사용자 모드 프로세스로 분리된 서브시스템을 지원하는 등 마이크로 커널 형태를 가지고있다. 이처럼 모든 운영체제는 하나의 구조만 선택해서 구현하지는 않고, 다양한 구조를 결합하여 성능과 보안, 편리성 문제들을 해결한다.
macOs와 iOS의 구조
사용자 경험
사용자가 컴퓨팅 장치와 상호작용할 수 있는 소프트웨어 인터페이스를 정의하는 층이다.
응용 프로그램 프레임 워크
Objective-C와 Swift 언어에 대한 API를 제공하는 층이다.
코어 프레임워크
그래픽 및 미디어를 지원하는 프레임워크를 정의하는 층이다.
커널 환경
Darwin이라고도 불리며, Mach 마이크로커널과 BSD UNIX 커널로 구성된 계층화된 시스템이다.
위의 그림처럼 응용 프로그램은 사용자 경험 층뿐만 아니라 응용 프레임워크나 핵심 프레임워크, 커널 환경과도 직접 통신 할 수 있다.
Darwin
트랩(Mach 시스템 콜)과 BSD 시스템 콜의 인터페이스를 제공한다.
프로세스, 스레드, 메모리 객체 및 포드 등을 커널 추상화를 통해 Mach의 기능을 제공한다.
Mach 및 BSD 외에도 장치 드라이버 및 동적 적재가능 모듈(커널 확장 또는 kext) 개발을 위한 I/O 키트 제공
Android 구조
Android는 그래픽과 오디오, 하드웨어 기능을 지원하는 프레임워크를 제공하며 계층화된 소프트웨어 구조를 가진다는 점에서 iOS와 유사하다.
ART
ART(Android RunTime)는 안드로이드 운영체제에서 앱을 실행하기 위해 사용되는, 모바일 장치에 최적화된 가상 머신이다. 바이트 코드를 AOT(Ahead-of-Time) 컴파일하여 기계어로 변환하여 실행할 수 있게 만들어준다.
네이티브 라이브러리
네이티브 라이브러리(네이티브 인터페이스)는 C나 C++, 어셈블리리 언어로 작성된 코드를 포함하는 라이브러리를 말한다.
HAL
HAL(Hadware Abstraction Layer)은 하드웨어 추상화 계층으로, 카메라나 오디오, 센서, 네트워크 인터페이스와 같은 다양한 하드웨어 기능을 지원한다. 이 기능을 통해 다른 하드웨어 플랫폼에서 이식 가능한 프로그램을 작성할 수 있다.
Bionic
Google에서 개발한 안드로이드를 위한 표준 C 라이브러리로, Linux의 표준 C 라이브러리인 glibc보다 메모리 사용량이 적고 모바일 장치의 느린 CPU를 위해 설계된 라이브러리이다.

운영체제의 부팅

운영체제의 부팅은 다음 순으로 진행된다.
부트 로더가 커널의 위치를 찾고, 커널을 메모리에 로드하여 실행한다.
커널이 실행되면서 하드웨어를 초기화하고, 루트 파일 시스템을 마운트 한다.
컴퓨터 시스템은 다단계 부팅과정을 거친다.
컴퓨터 전원을 켜면 BIOS라는 비휘발성 펌웨어에 있는 부트 로더가 실행되고, 이 부트 로더는 디스크의 특정 위치의 두 번째 부트 로더(부트 블록)를 로드한다.
부트 블록에 저장된 프로그램은 전체 운영체제를 메모리에 로드하고 실행한다.
GRUB는 Linux와 UNIX 시스템을 위한 오픈소스 부트스트랩 프로그램으로, 시스템의 부트 매개변수는 GRUB 구성 파일에 설정되어 실행 시작 지점에 로드된다. GRUB는 부팅 시 커널 매개변수를 수정하거나 부팅 시 다른 커널을 선택하여 실행하는 것도 가능하다.
모바일 시스템의 부팅 과정은 GRUB를 사용하지 않고 LK(Little Kernel)이라는 부트 로더를 사용한다.
대부분의 운영체제 부트 로더는 하드웨어 문제 진단이나 손상 파일 복구, 운영체제 재설치 등의 작업을 할 수 있는 복구 모드 혹은 단일 사용자 모드로 부팅할 수 있도록 한다.