
이번에 일주일간 OS 스터디를 하게되었다.
공룡책 이라고 불리는 유명한 저서인 "operating system concepts 10th"을 일주일동안 빡세게 공부하기로 했다.
앞으로의 글들은 공부하면서 이해한 내용을 내 나름대로 쉽게 풀어서 정리하기위해 쓰는 글이다.
일단 운영체제를 배우기 앞서, 운영체제의 개요를 쭉 훑어보자.
운영체제는 "하드웨어와 사용자 사이의 중개자" 역할을 한다.

컴퓨터를 새로 샀다고 가정해보자.
새로 컴퓨터를 사고 윈도우(운영체제)를 설치하지 않으면, 컴퓨터를 쓸 수가 없다.
윈도우를 설치해야 HDD, SSD에 저장되어 있는 프로그램들을 사용할 수 있고, 해당 프로그램들을 실행할 수 있다.
운영체제를 설치하면, 컴퓨터를 켰을 때 제일 먼저 운영체제가 실행되어 사용자에게 하드웨어에 접근할 수 있는 환경을 제공한다.
즉, 운영체제는 하드웨어를 사용할 수 있는 환경을 제공한다.
운영체제는 대부분의 컴퓨터 시스템에 사용된다.
PC, 노트북 같은 경우 Windows, Linux, MacOS가 많이 사용된다.
스마트폰은 Android, IOS가 많이 사용된다.
PC의 프로그램 실행이나 스마트폰의 터치스크린, 전화 하기, 메세지 보내기, 앱 실행 등을 할 수 있도록 해주는게 전부 운영체제가 해주는 것이다.
개발자로서 운영체제를 왜 알아야할까?
거의 모든 코드가 운영체제 위에서 실행되기 때문이다.
운영체제의 동작 방식을 잘 알면, 훨씬 효율적이고 안전한 프로그램을 만들 수 있다.
또한 운영체제를 공부하면서 하드웨어의 동작 방식도 알 수 있다.
개인적으로는, 프로그래밍을 하면서 몰랐던 미지의 세계를 알게되는 느낌이었다.

현대의 컴퓨터 시스템은 크게 CPU, 메모리, 입출력(I/O) 장치로 구분되어 있다.
각 구성요소들은 알맞는 컨트롤러에 연결되어 시스템 버스를 통해 서로 통신한다.
컨트롤러는 특정 유형의 장치를 담당하며, 컨트롤러 로컬 버퍼 저장소와 특수 목적 레지스터 집합을 관리한다.
컨트롤러는 장치 내부에 포함되어 있으며, 장치의 I/O 통신을 담당한다.
일반적으로 운영체제에는 각 장치 컨트롤러마다 드라이버가 있다.
드라이버는 컨트롤러의 작동을 잘 알고 있고 운영체제에 해당 장치에 대한 일관된 인터페이스를 제공한다.
또한 운영체제가 해당 장치를 인식할 수 있게 해준다.
특정 장치 컨트롤러에 연결된 장치와 운영체제간 통신을 원활하게 해주는 소프트웨어이다.
그래픽 카드를 꽂고 nvidia 그래픽 드라이버를 설치하는 것을 생각해보자.
그래픽 카드의 컨트롤러가 그래픽 출력을 담당하게 된다
그래픽 드라이버는 그래픽 카드와 OS간 통신을 중계하여, 사용자가 그래픽 카드를 최적으로 사용할 수 있게 해준다.
키보드로 문자를 입력하는 작업을 생각해보자.
이때 컨트롤러는 드라이버에게 작업 완료를 "인터럽트"를 통해 알린다.

하드웨어는 어느 순간이든 시스템 버스를 통해 CPU에게 인터럽트를 발생시킬 수 있다.
CPU가 인터럽트를 받으면, 하던 일을 중단하고 즉시 인터럽트 서비스 루틴을 실행한다.
인터럽트 서비스 루틴이 완료되면, CPU는 중단했던 일을 다시 재개한다.
CPU는 인터럽트가 발생했는지를 "인터럽트 요청 라인"을 통해 확인한다.
CPU는 하나의 명령어를 완료할 때마다 인터럽트 요청 라인을 확인한다.
인터럽트 신호가 있는 경우 "인터럽트 핸들러"가 해당 인터럽트 서비스 루틴을 실행한다.

현대 운영체제는 가장 긴급한 작업을 먼저 수행하기 위해 "인터럽트 우선순위 시스템"을 사용한다.
컴퓨터 시스템의 저장장치에 대해 알아보자.

위 그림에서 위에 있는 저장 장치 일수록 속도가 빠르고 용량이 적다.
일반적으로 프로그램이 실행될 때, 보조기억장치(SSD, HDD)에 있는 프로그램이 메모리(RAM)에 적재되고, CPU는 메모리로부터 명령을 가져와서 프로그램을 실행한다.
참고로, 컴퓨터 전원을 키면 가장 먼저 실행되는 프로그램은 "부트스트랩(bootstrap)" 이며, 운영체제를 실행한다.
부트스트랩은 EEPROM 과 같은 특수한 형태의 메모리에 저장된다.
인터럽트 장에서 설명했던 인터럽트 동작 방식을 다시 생각해보자.
해당 인터럽트 동작 과정은 소량의 입출력 작업에는 괜찮지만, 대용량의 입출력 작업에는 작업 시간동안 CPU를 사용하지 못하는 상황이 생긴다.
이러한 문제를 해결하기위해 현대 컴퓨터에서는 DMA(Direct Memory Access)가 사용된다.

DMA를 사용하면, CPU 관여 없이 입출력 장치가 직접 메모리를 읽거나 쓸 수 있다.
따라서, CPU는 다른 작업에 집중할 수 있고 입출력 작업의 효율이 향상된다.
하드 디스크, 네트워크 인터페이스 카드, 그래픽 카드 등 대용량 데이터 전송이 필요한 장치에서 주로 사용된다.
CPU가 완전히 사용되지 않는 것이 아니고, DMA가 입출력 작업을 보조함으로써 CPU 작업을 줄여주는 것이다.
현대의 CPU는 대부분 단일 칩의 다중 코어(Multi core) 시스템이다.

각 코어는 자체 레지스터와 L1 캐시라고하는 로컬 캐시 메모리가 들어있다.
L2 캐시는 각 코어들이 공유하는 캐시 메모리이다.
n개의 코어를 가지는 CPU는 운영체제에서 n개의 CPU처럼 보인다.
따라서, n개의 프로그램을 동시에 실행할 수 있다.
컴퓨터가 켜지면 부트스트랩 이라는 초기 프로그램이 실행된다.
부트스트랩은 하드웨어들의 상태를 초기화하고, 운영체제를 실행한다.
정확히는 운영체제의 커널을 실행한다.
운영체제의 커널이 실행되면 사용자에게 서비스를 제공할 수 있는 환경이 만들어진다.
사용자는 여러 개의 프로그램을 실행할 수 있다.
이때 실행 중인 프로그램을 "프로세스"라고 한다.
운영체제는 여러 프로세스를 동시에 메모리에 유지한다.

그림과 같이 메모리에 프로세스가 4개가 있는 경우, cpu는 프로세스들을 번갈아가며 실행하여 마치 동시에 실행하는 것처럼 보이게된다.
이는 "CPU 스케줄링"에 의해 수행된다.
운영체제는 잘못된 또는 악의적인 프로그램으로 인해 다른 프로그램이 실행되는 것을 방지해야한다.
시스템을 올바르게 실행하려면 "운영체제 코드" 실행과 "사용자 정의 코드" 실행을 구분할 수 있어야한다.
이는 "사용자 모드(user mode)"와 "커널 모드(kernel mode)"로 구분된다.
사용자가 실행한 프로그램이 하드웨어 자원을 필요로 하는 등의 요청이 필요할 경우, 프로그램은 커널 모드로 전환해야 한다.
이는 "시스템 콜"을 통해 이루어진다.

운영체제는 프로세스 관리와 관련해 다음과 같은 책임을 진다.
이러한 프로세스 관리 기법들은 뒤에서 자세히 다룬다.
메모리는 byte 단위의 저장 공간을 가진다.
각 저장 공간은 각각의 주소를 가진다.
메모리는 CPU와 입출력 장치간 공유되는 빠른 접근이 가능한 저장 공간이다.
운영체제는 메모리에 여러 개의 프로세스를 유지해야 하며 이를 위해 메모리 관리 기법이 필요하다.
이러한 메모리 관리 기법들은 뒤에서 자세히 다룬다.
운영체제는 물리적인 저장장치를 추상화하여 논리적인 저장 단위인 파일을 정의한다.
운영체제는 파일을 물리적인 저장장치로 매핑한다.
운영체제는 물리적인 저장장치를 파일로서 관리한다.
운영체제는 파일 관리를 위해 다음과 같은 일을 담당한다.
컴퓨터 시스템은 전원이 꺼져도 파일이 날라가지 않도록 보조기억장치를 사용한다.
대부분의 최신 컴퓨터들은 SSD, HDD와 같은 장치를 사용한다.
프로그램은 메모리에 적재되기 전까지 이러한 장치에 저장된다.
운영체제는 보조기억장치 관리와 관련하여 다음과 같은 활동을 담당한다.
특정 정보가 필요할 경우, 메모리가 아닌 캐시 메모리를 먼저 조사한다.
캐시 메모리에 있으면 해당 정보를 사용하고, 없으면 메모리에서 가져와야한다.
이때, 해당 정보가 다음에 또 사용될 가능성이 높다고 판단되면 캐시 메모리에 저장한다.
자주 사용하는 데이터는 캐시 메모리에 저장해서 메모리까지 찾아가지 않아도 되도록 한다.
메모리에 접근하는 것보다 캐시 메모리를 사용하는 것이 더 빠르다.
캐시 메모리의 크기는 매우 작으므로, 캐시 관리는 중요하다.