Computer Operating System
소프트웨어 엔지니어로서 보다 탄탄한 기초를 쌓고 싶다면 꼭 알아야 하는 개념가운데 한 가지가 운영체제(Operating System)이다. 컴퓨터 운영체제의 원리를 몰라도 프로그램을 만들 수는 있다. 사실 굉장히 많은 소프트웨어 개발자들이 운영체제의 원리를 모르면서도 잘만 돌아가는 유용한 프로그램을 만들어내고 있을 것이다.
하지만 소프트웨어 엔지니어로서 단순히 시키는 코딩만 하거나 정해진 언어와 라이브러리(library)만 갖고 일을 하는 환경에서 벗어나서 보다 다양한 분야에서 깊이 있는 일을 맡는 개발자가 되고 싶다면 운영체제에 대한 이해는 필수라고 생각한다.
지난번 글에서 정말로 소프트웨어의 동작을 한 땀 한 땀 이해하려면 C언어는 물론이고 그 아래의 어셈블리(Assembly) 언어 수준까지 내려가서, 내 프로그램이 실행되는 기계어까지 들여다보면 아주 좋다고 했었다. 하지만 기계어를 이해한다는 것이 기계어로 프로그램을 만든다는 이야기는 아니다. 지금은 아무도 그렇게 저수준의 언어로 소프트웨어를 만들지 않는다.
운영체제에 대한 이해도 마찬가지이다. 내 소프트웨어가 동작하는 기반 환경인 운영체제를 이해하는 것은 매우 중요하지만, 그것이 내가 직접 새로운 운영체제를 만들라는 의미는 아니다. 거의 대부분의 경우에 이미 만들어진 운영체제를 사용해서 소프트웨어를 개발하게 된다. 하지만 여기에 두 가지의 예외가 있다.
첫 번째는 정말로 간단한 운영체제를 만들어서 써야 하는 프로젝트의 경우이다. 소프트웨어의 적용 분야가운데 임베디드(Embedded) 시스템의 경우에는, 여러 가지 이유로 직접 간단한 스케줄러(Scheduler)와 메모리 매니저, 태스크(Task) 간 통신 혹은 장치 드라이버 인터페이스를 만들어야 하는 경우가 있다.
운영체제가 하는 일이 무엇인가? 프로그래머가 만들어야 하는 응용 프로그램과, 그 프로그램이 실행되는 하드웨어 사이의 가교 역할을 해 주는 것이다. 응용 프로그램을 만드는 사람들이 하드웨어의 자세한 사항들을 알지 못해도 이런 장치를 편하게 사용하고, 또 컴퓨터에서 동작하는 다른 프로그램들과의 상호 작용을 일일이 관리하지 않아도 알아서 서로 조화롭게 동작하도록 중재를 해 주는 소프트웨어를 운영체제라고 한다.
그런데 일부 임베디드 시스템의 경우에는, 이런 운영체제를 돌리기에 컴퓨터의 성능이나 메모리의 크기가 충분하지 않은 경우가 있다. 다양한 하드웨어를 지원하기 위해서 만들어진 일반적인 운영체제에는 내 프로젝트에서 사용하는 하드웨어나 필요한 기능에 비해서, 여러 가지 추가적인 기능들이 들어가 있어서 너무 무겁고 비 효율적이라는 판단을 내릴 수 있다.
이럴 경우에 내 응용 프로그램에서 꼭 필요한 기능을 직접 만들어서 사용한다. 이런 것은 사실 운영체제라고까지 부르기는 좀 그렇고, 스케줄러나 펌웨어(Firmware) 혹은 모니터 프로그램 등으로 부르기도 하는데, 영어로 이런 환경을 베어메탈 (Baremetal)이라고도 한다. 운영체제 없이 바로 하드웨어 위에서 응용 프로그램을 만든다는 의미이다.
두 번째의 경우에는 운영체제를 쓰긴 하는데, 그 운영체제가 제공하는 성능이나 기능이 목적에 맞지 않을 경우 수정해서 사용하는 경우이다. 물론 이런 경우에는 소스코드가 제공되는 환경에서 스케줄링 방식이던 메모리 관리 혹은 프로세스/태스크 간 통신 등 운영체제의 일부 기능을 수정해서 쓰는 방식이긴 한데, 기존 운영체제의 동작 방식을 잘 이해하고 있어야 내가 원하는 부분을 수정해서 쓸 수 있게 된다.
이런 예외적인 경우가 아니라면 주어진 운영체제 환경에서 프로그램을 만들게 되는데, 마이크로소프트 윈도나 애플의 맥 OS같이 소스코드도 공개되어있지 않고, 개발 환경도 잘 갖춰져 있어서 내부 동작을 알기도 힘들고, 잘 몰라도 그냥 시키는 대로 프로그램을 짜면 웬만큼 잘 돌아가는 환경이라면 좋은 공부가 되지 않는다.
우분투를 비롯한 리눅스 환경은 소스코드가 공개가 되어있고, 워낙 다양한 커널과 배포판들이 있어서 프로그램을 만들기 불편한 부분도 있지만 반면에 본격적으로 운영체제를 공부하기는 좋다. 그런데 문제는 소스코드의 크기가 천만 라인이 넘을 정도로 방대해서, 기반 지식 없이 다짜고짜 공부하기에는 좀 어려울 수도 있다는 것이다.
임베디드 운영체제는 윈도나 리눅스 같은 범용 운영체제에 비해서 간단하게 설계되어 있어서 공부를 하기는 좋은데, 상용으로 많이 쓰이는 실시간 운영체제 (Real Time Operating System)의 경우에는 소스코드를 구하기도 어렵고, 유명한 운영체제의 경우에는 대략 백만 라인이 넘는 정도의 소스코드 양을 자랑한다. 물론 커널(Kernel)만 보면 그 정도는 아닌데, 네트워크 스택을 포함한 각종 미들웨어 및 하드웨어 지원을 위한 디바이스 드라이버를 포함하면 꽤 덩치가 커지게 된다.
위키피디아의 임베디드 운영체제 항목을 보면 정말로 다양한 종류의 플랫폼이 존재하는데, 그나마 추천하고 싶은 것은, 소스도 공개되어 있고 문서도 잘 되어있으며 책도 많이 나와있는, 아마존에서 지원하는 FreeRTOS라는 플랫폼이다. 찾아보니 커널 소스도 만 라인 정도라고 하고, 문서를 한번 살펴봤는데 운영체제의 기본 기능을 나름 충실하게 구현하고 있으며, 지원되는 하드웨어도 많이 있어서 실제로 돌려보면서 깊이 있게 이해하기 좋을 것 같다.
컴퓨터 아키텍처의 이해라는 글에서 추천한 방법이, “Hello World”라는 프로그램이 어떻게 실행되는지 한 줄 한 줄 다 따라가면서 이해해 보라고 했었는데, 똑같은 방법을 운영체제에도 적용할 수가 있겠다. 내가 만든 정말 간단한 프로그램이 어떻게 스케줄러에 의해서 실행이 되고, 내가 호출한 printf()라는 함수가 어떻게 C 라이브러리 함수를 거쳐서 운영체제의 시리얼 포트 디바이스 드라이버의 출력 버퍼로 원하는 문자열을 집어넣고, 어떻게 한 글자 한 글자씩 직렬 포트를 통해서 임베디드 컴퓨터와 내 개발 PC 사이에 통신이 이루어지는지를 다 분석해서 이해할 수 있으면 그 운영체제의 매우 많은 부분을 이해한 것이라고 볼 수 있겠다.