운영체제는 컴퓨터가 발전하면서 같이 발전하게 되었다. 초기 컴퓨터는 크게 3가지로 구성되었다. 카드 리더, 프로세서, 프린터이다. 카드 리더는 입력기이다. 입력은 종이에 입력할 코드에 맞는 구멍을 뚫어서 넣어주는 방식이었다. 프로세서는 현재와 비슷한 계산하는 역할이었고, 프린터는 입력에 대한 결과를 종이에 찍어서 보여주었다. 이 시기에는 운영체제도 존재하지 않았으므로, 오퍼레이터(operator)라는 컴퓨터를 사용하는 직업이 따로 있었고, 컴퓨터의 크기 또한 너무 커서 건물 전체를 사용해야할 정도였다.
위에서 초기 컴퓨터의 상황을 살펴보았는데, 프로그램을 수행할 때마다 컴파일->링크->로딩 순서를 오퍼레이터가 직접 입력해주었다. 이러한 과정을 자동화한 것이 batch processing system 이다. 위 과정을 하나의 프로그램으로 작성하여 프로세서의 메모리안에 할당해주었는데, 이 프로그램을 resident monitor라고 불렀다.
resident는 "거주" 라는 의미로 이 프로그램이 항상 프로세서안에서 거주한다는 의미로 이러한 이름을 사용하였다. 그리고 이것이 최초의 운영체제로 알려져 있다.
과거에는 컴퓨터가 매우 비싼 장비였다. 그리고 초창기 메모리의 상태는 resident monitor를 제외하고 단 하나의 애플리케이션만을 할당하여 사용하였다. 하지만 이는 매우 비효율적인 방법이었다.
프로그램을 수행하는 도중에는 계산을 하는 CPU 외에도 입출력을 담당하는 I/O장치가 수행한다. 즉, CPU와 I/O장치가 교대로 동작하는데 I/O장치가 수행하는 동안에는 CPU가 아무것도 할 일이 없었다. CPU가 아무일도 안하는 상태를 idle 상태라고 말한다. 그리고 I/O장치는 CPU에 비해 매우 느리기때문에 idle 상태의 비율이 너무 높았다. 이러한 비효율적인 수행을 해결하기 위해 multiprogramming system이 나왔다.
Multiprogramming system은 메모리에 여러 애플리케이션(프로그램)을 올리는 시스템이다. 예를 들어 user1, user2 두 개의 애플리케이션이 있을 떄, 처음에는 user1에서 CPU 수행을 하다가 I/O장치 수행으로 넘어간다. 이 순간 CPU는 idle 상태에 있지 않고 user2가 있다는 것을 보고 user2의 CPU 수행을 시작한다. 이렇게 idle상태의 시간을 최대한 줄이고자 하였다.
하지만 메모리에 여러 프로그램을 올리면서 많은 문제점이 발생했다. 가장 큰 문제점은 CPU가 어느 프로그램을 수행해야하는지 선택하는 것이다. 이러한 작업을 CPU 스케줄링이라고 하며, 이는 운영체제의 중요한 역할 중 하나이다. 그리고 새로 들어온 프로그램을 어느 메모리 공간에 할당해야하는지도 큰 문제였다. 이 역시 운영체제 역할 중 하나이다.
시간이 지나 모니터와 키보드를 사용하면서 사용자와 컴퓨터 사이에 대화 형식이 가능해졌다. 하지만 여전히 컴퓨터 자체가 너무 비쌌기 때문에 아래와 같이 단말기(terminal) 형태로 사용하였다.
각 사용자(User)들은 모니터와 키보드만을 가지고, 실제 프로세서는 하나의 단말기에 존재하여 이를 공유하여 사용하였다. 멀티 프로그래밍에서는 이와 같은 단말기 형태에서 문제가 생긴다.
예를 들어, 단말기 메모리에 User1 프로그램, User2 프로그램, User3 프로그램이 할당되어 있고 User1이 먼저 CPU를 사용한다고 하자. 멀티프로그래밍에서는 User1이 CPU를 수행하고 있는 도중에는 다른 사용자는 CPU자체를 사용할 수 없다. (CPU가 하나인 환경) 그러므로 다른 사용자들은 User1이 CPU수행을 모두 마칠 때까지(또는 I/O를 만날 때까지) 기다려야한다. 하지만 이는 매우 비효율적이다.
이를 해결하기 위해 나온 것이 time-sharing system이다. 시분할 시스템은 CPU가 하나의 프로그램을 수행하는 시간을 제한하는 것이다. 예를 들어, User1 프로그램을 일정 시간 수행하면 반드시 다음 프로그램으로 넘어가서(스위칭, switching) 또 다시 일정 시간을 수행한다. 이렇게 일정 시간을 두어 프로그램들을 번갈아 수행하면서 모든 프로그램이 공평하게 수행이 되도록 한다. 그리고 이 일정 시간은 매우 짧은 시간(ms)이므로 CPU가 하나인 환경에서도 여러 사용자가 동시에 사용하는 듯한 효과를 가져온다.
시분할 시스템을 사용하면서 여러 사용자(프로세스)간에 통신이 가능해졌다. 하지만 여기서도 역시 멀티프로그래밍에서와 같은 스케줄링과 메모리 문제가 있었다. 이를 해결하기 위해 동기화 기술, 가상 메모리 등이 이후에 나왔다.
현대 운영체제는 인터럽트 기반 시스템이다. 그렇다면 인터럽트는 무엇인가?
컴퓨터에 전원이 들어오면 위에서 말했듯이 부팅이 시작된다. 먼저, POST과정이 시작되고 그 후에 부트 로더가 하드 디스크에 있는 운영체제 프로그램을 RAM에 가져와 할당한다. 할당된 운영체제는 컴퓨터의 전원이 꺼질 때까지 상주(resident)한다.
부팅이 끝나고 운영체제가 동작하는 동안 수 많은 인터럽트가 발생할 수 있다. 예를 들어, 사용자가 마우스를 움직인다고 가정하자. 이 동작을 컴퓨터는 어떻게 알 수 있을까? 바로 인터럽트를 통해 알 수 있다. 마우스를 움직이는 순간, 마우스에서 인터럽트 전기 신호가 발생하여 이를 CPU에게 보낸다. CPU는 이를 감지하고, 자신이 하던 일을 멈춘 후에 이 인터럽트 신호를 처리하기 위해 운영체제 내부에 있는 인터럽트를 처리하는 코드(interrupt service routine, ISR)로 이동한다. 이 곳에 마우스가 움직일 때 어떻게 동작해야하는지가 내포되어 있어 이를 수행한다.
마우스 뿐만 아니라 키보드 역시 동일하게 동작한다. 이러한 하드웨어에서 발생한 인터럽트를 하드웨어 인터럽트(Hardwore Interrupt) 라고 한다. 인터럽트라고 하면 기본적으로 하드웨어 인터럽트를 말하지만, 소프트웨어에서도 인터럽트를 요청을 할 수 있다. 이를 소프트웨어 인터럽트(Software Interrupt) 라고 한다. 소프트웨어 인터럽트는 명령어로 직접 인터럽트 전기 신호를 CPU에게 보낼 수 있다. 즉, 프로그램에서 swi
, int
와 같은 어셈블리어 명령어를 수행하는 것이다. (명령어는 운영체제마다 다르다.)
예를 들어, 마우스로 워드 작성 프로그램을 실행시킨다고 하자. 워드 작성 프로그램을 실행시키는 것까지는 하드웨어 인터럽트가 수행된다.(마우스가 이동하여 더블 클릭으로 실행하는 경우이다.) 이 프로그램에서 사용자가 하드디스크에 있는 다른 워드 파일을 읽고 싶은 경우, 소프트웨어 인터럽트를 발생시킨다. 소프트웨어 인터럽트 역시 하드웨어 인터럽트와 동일하게 운영체제 내부에 해당 인터럽트를 처리하는 코드(ISR)가 존재하여 이 곳으로 이동한다. 여기서 하드디스크에서 읽을 파일을 찾아서 반환해주는 수행을 처리하는 것이다.
마지막으로 내부 인터럽트(Internal Interrupt)가 있다. 내부 인터럽트는 프로그램을 수행하는 도중에 발생하는 예외 상황을 처리한다. 대표적인 예로 0으로 나누는 동작이다. 프로그램의 내부에 result = a / 0;
이와 같은 코드가 있을 때, CPU는 내부 인터럽트를 발생시켜 운영체제안에 있는 ISR로 이동한다. 이 경우에는 DividedByZero
라는 ISR로 이동한다. 여기서 잘못된 동작을 수행한 프로그램을 강제로 종료시킨다.
운영체제는 평소에는 대기 상태에 있으면서 인터럽트가 발생하는 순간 작업을 수행한다. 그 인터럽트의 종류에 따라 운영체제 내부에 위치한 ISR로 이동하여 그에 맞는 처리를 한다. 위에서 설명한 하드웨어 인터럽트 과정을 그림으로 간단히 표현하면 아래와 같다.
위 그림은 사용자 애플리케이션을 실행하기 위해 하드웨어를 사용하는 모습이다. 애플리케이션이 실행하는 중에도 계속해서 인터럽트는 발생한다. 워드 작성 프로그램을 예를 들면 키보드로 글을 작성하는 경우, 하드디스크에 있는 파일을 불러오는 경우 모두 인터럽트가 발생한다. 그러므로 CPU는 애플리케이션과 운영체제 내부를 교대로 수행하는 모습을 볼 수 있다.
정리하면, 인터럽트는 CPU에게 보내는 전기 신호로서 인터럽트가 발생하면 CPU는 하던 일을 중지하고 해당 인터럽트를 처리하기 위해 운영체제 내부에 있는 ISR로 이동하여 수행한다. 그리고 수행이 끝나면 원래 위치로 돌아간다. 인터럽트는 하드웨어 인터럽트, 소프트웨어 인터럽트, 내부 인터럽트로 총 세 가지가 존재한다.
잘 읽었습니다.