운영체제 개발 관련 내용이 좀 뜸한 이유

저 스스로의 자료를 만들기 위해서 예전부터 여러모로 보던 자료들을 막 꺼내보는데… 너무 많군요. (변명인가…ㅠㅠ)

그래서 제가 연구실 초창기에도 자료가 많았나 싶었는데…

초창기에는 운영체제 이론 관련된 자료가 얼마 없엇네요… (학부연구생 시절)

저게 진짜 초창기에 연구실의 제 책상 꼬락서니였는데…

이때 이후로 운영체제 개발 관련 이론 책들이나 여러 책들 쫙 다 모였던 거 같군요. 근데 그 당시 사진들이 없어..ㅠㅠ

그리고 그걸 운반하는 데 봉고 트럭 한대로 해서 시골에 아버지 공장 창고에 옮겼습니다.

그리고 그거 꺼내오면서 하나하나 보는데…

이 내용들을 가지고 직접적인 자료로 만들려니 여러모로 힘드네요.

그림도 제가 이해하기 쉬운 형태로 해서 그러보려고 노트에 직접 그려서 올리는…

제가 직접 그리는 데 이용하는 노트입니다.
이런 걸 다 그리고 있습니다. 미리 여러장 다 그러놔서 뒤에 흔적이 보이는…;ㅅ;

그러면서 내용 정리도 좀 하고..

운영체제 개발이니 진짜로 개발도 시행착오 거쳐가면서 좀 하고 있고…

그러면서 블로그 내용으로 정리하고…

취준하고….

그래서 좀 뜸하네요. 대신 지금은 플젝이 없어서 취준이 비중이 제일 높긴 합니다만, 취준으로 머리아픈 거 해소하면서 시작한 거라 뜸해요. ;ㅅ;

그래도 올립니다.

운영체제 개발 – 부트로더 선택(?!)

운영체제는 일반 응용 프로그램과 시작점이 다른 것이 있다면, 메모리에 올리는 녀석이 있냐 없냐의 차이로 보면 쉽게 이해된다. 리눅스의 응용 프로그램이던 윈도우의 응용 프로그램이던, 실행 명령을 입력받는 운영체제가 존재하고, 실행을 하면 운영체제가 해당 프로그램의 실행 정보를 메모리에 올린다. 가상 머신을 쓰는 환경들은 더더욱 쉽다. 자바, 안드로이드를 예로 보면, 자바 프로그램은 바이트코드화 되어서 자바 가상 머신(JVM)에 올라간다.

자바 떡칠인 모 반도에 맞는 설명… (좋은 소리 아니다.)

근데 운영체제는? 운영체제를 실행할 무언가는? 운영체제를 메모리에 올릴 무언가는? 그런 거 없다. 하나하나 직접 올려야 한다. 그걸 위해서 개발해야 하는 것이 바로 부트로더이다.

부트로더는 이런 일들을 주로 한다.

  • 커널(및 모든 커널 부트스트랩 필요)을 메모리로 가져오기
  • 커널에 올바르게 작동하는 데 필요한 정보 제공
  • 커널이 좋게 동작하는 환경으로 전환
  • 커널로 제어 전송

뭐, 이런 기능을 제공하기 위해서는 운영체제 개발 책들에서는 운영체제 로드를 위한 부트로더 개발 작업을 어셈블러로 작성하고 그걸 설명해주는데도 여러모로 시간을 잡아먹는다.

그러면 좋은 것이 컴퓨터 리소스를 쓰기 위해서 16비트 모드, 32비트 모드를 직접 작업해서 넘어오는 걸 해보게 된다. 20비트 세그먼트 가지고 1MB 메모리 주소에 접근하고 그걸 가지고 시작하는 CPU를 제어할 수 있는 하드웨어 종속적인 코드 짜고, 이걸 32비트, 64비트 모드로 점점 넘어오는 작업을 해야 하는 그런 일들을 하고 해서 이제 화면 접근 작업을 통해서 “Hello World!” 찍어내는데만 엄청나게 시간 소요를 하게 되어주는….

이렇게 생각하고 포기해서 1장이나 2장에서 멈춘 당신, 뜨끔합니까?

저러다가 요즘 윈도우 10에서는 저 영역을 건드리지 못하게 막아내는 거 땜에 오류 팍팍 떠서 걍 멘붕하고 포기하는 당신…

부트로더는 개발해서 나쁠 건 없다. 근데 수많은 운영체제 제작 코드들이 자신만의 코드를 이용해서 개발하고 한다면… 운용하기 힘들어진다. 게다가 요즘처럼 다른 플랫폼까지 이용해야 하는 경우라면…? 더더욱 개발 힘들어진다. 아키텍쳐마다 비트 모드에 접근하고 사용하는 방식 자체가 다르다.

해봐서 좋은 경험이 된다. 근데 커널 자체에 집중해서 개발하는 것을 위해서 요즘은 그냥 일련의 커널 로딩 과정을 간편하게 해주기 위해 부트로더를 이용한다. 흔히 대표적으로 이용하는 것이 바로 GRUB인데, 이녀석을 이용하여 개발하는 걸 보여주려고 한다.

부트로더 직접 개발하면 진짜 피곤하다.

부트로더 직접 개발하는 거 어떤지 알고 싶으면 한승훈 저자님의 “64bit 멀티코어 OS 원리와 구조” 이 책 보고 직접 스터디 해봐도 된다. 근데 아마 도서관에 1권만 스터디한다면서 이미 다 빌려가고 없거나 할 수도 있다. ㅇㅅㅇ;;

운영체제 이론 – 스택

스택은 FILO(First in last out이라고도 함) 형태의 자료구조로, 마지막에 입력된 자료가 먼저 나오는 형태이다. 반대로 FIFO(First in first out이라고도 함) 형태의 자료구조는 큐가 있는데, 이건 먼저 입력된 자료가 먼저 출력되는 형태를 가진다.

스택의 구조

이런 자료구조에서 보던 녀석을 왜 운영체제 이론 설명하는데 굳이 끼우냐면… 여러모로 볼 녀석이다. 진짜로….

이런 반응 나올 정도로 지겹게 볼 것이다. 그러니 읽는 분이 자료구조 개판으로 공부했다면 운영체제 공부는 엄청나게 괴로운 공부가 될 것이다. 진심어린 충고다.

콜스택은 특정 함수가 호출될 때에는 지역변수나 함수 파라미터가 특정 공간에 저장되는데 이 공간을 말한다. x86 아키테겨에서는 스택에 변수나 파라미터가 저장될 때 주소 공간이 줄어드는 방향으로 데이터가 저장된다. 이걸 설명하기 위해 다음과 같은 함수가 있다고 보자.

example code

이런 함수를 호출할 때의 콜 스택에 대해서 손으로 직접 그려보았다.

콜스택 상황

함수의 수행이 끝날 경우에는 이 함수를 호출한 실행 코드의 위치로 돌아갈 필요가 있다. 이때 필요한 값은 해당 함수의 복귀 주소와 EBP값이 필요하다. 이런 값들은 함수를 호출할 때마다 자동으로 생성되는데, 이러한 값들의 모음을 스택 프레임(Stack Frame)이라고 한다. 콜스택의 실제 상황을 직접 그린 이유는 이걸 가지고 스택 프레임에 들어갈 포인터 녀석들을 설명하려 한다.

  • ESP(Extended Stack Pointer) 레지스터
    스택의 밑바닥을 가리키는 포인터다. 최초 함수가 호출될 때 EBP와 ESP의 값은 같은 값이며, 로컬변수가 선언되면 ESP는 낮은 값으로 증가한다. (x86 아키텍쳐를 기준으로 설명한다.) ESP는 다음 데이터를 push할 위치가 아니라 pop했을 때 뽑아낼 데이터의 위치를 가리킨다. (이거 헷갈린다.)
  • EBP(Extended Base Pointer) 레지스터
    스택 프레임의 시작 주소를 가리킨다. 새로운 함수가 호출되면 파라미터와 스택 프레임 값이 스택에 채워지는데 EBP 레지스터값은 바로 그 다음 주소를 가리킨다. 즉, 호출된 함수가 로컬 변수를 선언하기 직전의 시작점이 되며 EBP값은 함수 실행 동안 변하지 않으므로(다른 함수를 호출하지 않는 이상 안변함) 파라미터나 로컬 변수를 참조할 수 있는 기준점이 되어준다. EBP 레지스터는 현재 실행중인 함수가 종료되어 리턴되면 이 함수를 호출한 함수의 EBP값으로 변경된다. (스택 프레임에 저장된 EBP값)

프로세스를 적고 정리하면서 거의 항상 꼭 보는 스택과 실제 실행과 관련된 내용에 대해서 정리를 해봤다. 어려운 내용은 아니지만 머릿속엔 있는 게 좋다.

운영체제 이론 – 스레드

프로세스가 프로그램의 주체라면 스레드는 프로세스의 실제 실행 단위이다. 프로세스는 여러개의 스레드를 담고 있으며 커널은 프로세스가 담고 있는 스레드를 관리해서 프로세스의 동작을 조정한다.

가상주소 공간을 공유하고 있는 스레드의 모습을 그려봄…

위에 그린 그림은 스레드가 프로세스의 자원을 공유하는 것을 표현했다. 코드 영역을 동시에 접근하는 것은 문제가 되지 않지만 쓰기 가능한 데이터 영역에 동시에 접근할 경우에는 데이터 무결성 장애를 일으킬 수 있다. 스택은 스레드 고유의 자원이며, 일반적인 경우에는 다른스레드의 간섭을 받지 않는다. 따라서 동기화 걱정 없이 마음대로 이용할 수 있다.

스레드 경합은 자료구조나 데이터에 복수의 스레드가 접근하면 문제가 발생할 수 있는 것을 나타낸다. 이런 상태를 경쟁 상태, 경합 상태라고 하는데, 의외로 쉽게 일어난다. 아래 예시 코드처럼 짜면 거의 반반의 확률로 발생한다.

스레드 경합 관련 예시 코드. 잠안와서 작성한…(?!)

단위 연산이 아닌 작업이 들어있기 때문에 실제로 출력되는 것은 1,1 혹은 1,2가 된다. 이런 문제를 해결하기 위해 동기화를 적용해야 한다. 그리고 그 동기화를 적용하기 위해서 동기화 객체를 사용하여 구현을 하는데 그것들은 다음과 같다.

  • 크리티컬 섹션
  • 뮤텍스
  • 세마포어
  • 스핀 락

이것들에 대한 건 운영체제 책에서 더 자세히 볼 수 있으니 자세한 복습은 운영체제 내용을 참조한다.

TCB(Thread Control Block)은 프로세스에 PCB가 존재하듯, 스레드에도 스레드 정보를 관리하기 위한 블록이 존재한다. TCB는 커널에서 스레드를 관리하기 위해 필요로 하는 정보를 담고 있는 구조체이고, 그 구조는 아래 그림과 같다.

PCB와 TCB의 관계를 보여줌..

그리고 다음과 같은 정보들을 가지고 있다.

  • 스레드 식별자: 고유 아이디는 스레드마다 새롭게 만듬.
  • 스택 포인터: 스레드의 스택을 가리키는 포인터
  • 프로그램 카운터: 스레드가 현재 실행 중인 명령어 주소
  • 스레드 상태: 실행, 준비, 대기, 시작, 완료
  • 레지스터 값들
  • 스레드를 담고 있는 프로세스의 PCB의 포인터

스레드에 대해서는 이정도만 정리해도 충분할 것이다. 간단한 거라서 밤 늦게 정리를 해보고 자려고 한다. ㅇㅅㅇ

그럼 전 일단 자러….

운영체제 이론 – 프로세스

본인이 뭐 어느 정도의 주니어 혹은 시니어 프로그래머 이상급 된다면 사실 이런 내용은 이미 다 알고있는 것일껍니다. 그런 게 아니라서 뭐 간단한 정리를 보고 싶으시다면 이 글이 도움이 되었으면 좋겠군요.

쓸데없이 서론이 길어졌다. ㅠㅠ 오랜만의 블로그라….

그럼 시작해보겠습니다. 주요 용어에 대해 볼드체를 처리했고, 그에 대한 내용을 풀어가는 형태로 글을 써봤습니다.

프로세스는 컴퓨터에서 실행되는 프로그램을 의미합니다. 일반적으로 프로그램은 하드디스크에 저장되어 있는데 프로그램을 실행하면 운영체제의 로더에 의해 메모리로 적재됩니다. 이렇게 메모리에 적재되어 실행되는 프로그램을 프로세스라고 합니다.

싱글테스킹은 운영체제에서 하나의 프로세스가 독점적으로 시스템 자원을 사용하는 것이고, 멀티태스킹은 운영체제에서 하나의 프로세스가 독점적으로 시스템 자원을 사용하는 것을 막기 위해 프로세스에 자원 사용 시간을 적절히 배분하여 이용합니다.

프로세스가 메모리에 로드되었을 때의 대략적인 녀석은 다음과 같습니다.

이미 운영체제 시간이나 프로그래밍 시간에 다 배운 녀석이죠…ㅇㅅㅇ;;

프로세스 컨텍스트(Process Context)는 프로세스 문맥이라도고 하며, 운영체제가 관리하는 프로세스 정보라고 보면 된다. 주로 다음과 같은 녀석들이다.

  • CPU 상태: CPU 레지스터, 현재 프로세스가 수행되고 있는 위치 등 (ex: instruction pointer)
  • PCB(Process Control Block): 커널이 관리하는 프로세스 정보 구조체
  • 가상주소공간 데이터: 코드 데이터, 스택, 힙

위와 같은 내용이 프로세스 컨텍스트를 의미한다. 멀티테스킹 운영체제에서 실행되는 프로세스는 위와 같은 정보를 토대로 커널이 프로세스를 실행하고 있다는 것을 의미하며 컨텍스트 스위칭은 지금 실행하고 있는 프로세스의 실행을 멈추고 다른 프로세스의 컨텍스트를 가져와 실행함을 의미한다.

PCB(Process Control Block)는 운영체제 커널의 자료구조로써 프로세스를 표현하기 위해 사용된다. 커널은 이 자료구조를 사용해서 프로세스를 관리한다. PCB는 프로세스가 생성될 때 같이 생성되며 프로세스 고유의 정보를 포함한다. Win32 프로세스에서의 PCB 구조는 교과서 같은 곳에 많이 나와있는데, 외우고 있는 걸 노트에 그려봤다.

(이런 걸 외우고 있으니 머리가 이상해지는 겁니다, 규링!) (응?)

PCB는 체인으로 다른 PCB랑 연결되어 있다. (우리는 이런 걸 흔히 링크드 리스트라고 한다.) PCB에 포함된 정보가 글씨가 좀 지저분한데… 정리하면 다음과 같이 볼 수 있다.

  • OS가 관리상 사용하는 정보: vm로세스 상태, 프로세스 ID, 스케쥴링 정보, 우선순위 등
  • CPU 수행 관련 하드웨어 값: 프로그램 카운터, 레지스터 등
  • 메모리 정보: 코드, 데이터, 스택의 위치 정보
  • 파일 정보: 열어둔 파일 정보(핸들)

프로세스 상태는 컨텍스트 스위칭에 의해서 프로세스는 실행 상태에 놓일 수도 있고, 정지 상태에 놓일 수도 있는데, 이를 운영체제 교과서에서 이렇게 표현한다.

프로세스 상태 다이어그램

프로세스 상태에 대해서는 아래와 같이 정리해보자.

  • 실행
    프로세스가 CPU를 점유하고 있는 상태.
  • 대기
    프로세스가 CPU를 점유하기 위해 기다리고 있는 상태. 메모리에는 이미 올라와 있을 뿐 아니라 CPU 동작을 위한 모든 조건들을 만족한 상태이다.
  • 블록(wait, sleep)
    당작은 작업이 수행될 수 없는 상태. sleep 함수나 동기화를 위해 대기해야 할 경우에 프로세스는 블록 상태가 된다.
  • 정지
    스케쥴러나 인터럽트 때문에 비활성화 된 상태. 외부에서 다시 재개시켜야 활성화 상태로 변경된다.

컨텍스트 스위칭(Context Switching)은 CPU가 한 프로세스에서 PCB 정보로 스위칭 되는 과정을 의미한다. 그 과정도 일단 손으로 그려보았다.

프로세스 컨텍스트의 스위칭 과정. 스위칭 과정은 엄청 짧으나 v 체크 되어있는 만큼의 작업을 하고 있는 것이다.

위에 그림에서 보면 두 프로세스가 실행과 중지를 반복하여 컨텍스트 스위칭 되는 과정을 보여준다. 프로세스 1이 실행중에 있다가 컨텍스트 스위칭이 발생할 경우, 운영체제는 프로세스 1의 PCB를 저장한 뒤 프로세스 2의 PCB를 복원시킨다. 그러고 나서 프로세스 2의 실행이 진행된다. 그러다가 다시 프로세스 1을 실행할 때에는 프로세스 2 PCB를 저장하고 프로세스 1의 PCB를 불러온다. 이런 과정을 반복하면서 두 프로세스는 실행과 중지를 반복한다. 컨텍스트 스위칭은 시스템 콜이나 외부 인터럽트에 의해서 주로 발생한다.

프로세스에 관해서 간단하게 정리해보면 이 정도가 될 듯 하다. 너무 간단하게 적긴 했다만… 자세한 걸 보고 싶으면 운영체제 책을 가지고 제대로 공부하면 된다.

다음 글에서는 스레드에 대해서 지금처럼 간단하게 작성하려 한다.

p.s. 너무 오랜만에 글을 썼는데… 앞으로 자주 쓰려고 합니다. ;ㅅ;

운영체제 이론 – 시작

운영체제 이론은 사실 대학 다니면서 꼭 배우는 거지만… 운영체제를 직접 개발하려고 하면 반드시 꼭 정리 다시 해야 한다.

니가 아는 걸 직접 짜야 하는 걸 보게 된다.

즐거운 거잖아…!!!!!!

(저리가 by 독자)

그러니 일단 이론도 좀 시작해봅니다.

일을 막 늘리는 거 같아 보이면 기분탓입니다.

Swift는 배우기 어려운가?

결론적으로 이야기 하면 아니다라고 해야 하는데…. 난감하다.

왜냐..?

매년 버전이 올라가고 있어서 따라가기 힘들어서 배우기 어렵다는 게 맞는 듯 하다.

스위프트도 그렇고, 코틀린, Go 등 요즘 나오는 언어들은 배울 때 어렵게 배우는 것들이 없다고 본다. 공식 홈페이지에 도큐먼트들도 너무 잘나온다.

그런데도 불구하고 왜 아이폰 앱 개발이 어렵다고 하는 걸까에 대해서 밖에서 떠들다가 스위프트가 배우기 어려운 언어인가를 생각하니… 난 개인적으로는 아닌 듯 하다.

것보다 Objective-C를 쉽게 써먹던 나날이 있다보니….

Objective-C가 쉽다면 뭔 변태야라면서 이렇게 반응할 분들이 있긴 하다만….

근데 왜 이럴까..?

버전이 계속, 그것도 빠른시간안에 계속 올라간다는 것은 여러모로 개발자들한테 불안감을 주고 있는 것은 확실하다는 느낌이 든다. 지금 Go 쓰려다가 갈아엎고 다시 이전에 쓰던 것들로 돌아가는 케이스도 너무 봤다. 특정 버전, 특정 환경 기준으로 개발을 했는데 업데이트 된 거에는 그게 맞는건지 아닌지도 모른다… 이거 무지 어려운 거다.

지금 스크립트 언어 중에 그렇게 해서 난이도 개판된 것이 바로 루비랑 레일즈다. 특정 버전에서는 아예 설치 스크립트랑 언어 인스톨러 오류 땜에 일어나는 문제가 개발자 문제인지 어려워할 정도의 시절도 있다. 이게 좀 빨리 고쳐져서 다행이었지만 솔직이 이 때에 뭔 버전이 있었고 뭐가 바뀌었는지는 이미 머릿속에서 지워졌다. 그만큼 오류땜에 시달린 인상이 강하기 땜에….

스위프트도 지금 그런 상황인 듯 하다. iOS 업뎃도 매년 이루어지면서 프레임워크, 개발 환경도 계속 갈아엎혀서 답답한데 거기에 언어까지 그러니 더더욱 답이 없을꺼다.

뭐, 그래도 기본적인 문법 제대로 익히고, 제대로 앱 한번 개발해보고 나면 사실 다 그냥 지나갈 이야기이지만….

그렇다고 이렇게 반응해주진 마세요… 상처입어요. ㅠㅠ