본문 바로가기
computer science/운영체제

[운영체제] 시스템 구조와 프로그램 실행

by 박연호의 개발 블로그 2020. 4. 22.

이번 시간에는 시스템 구조와 프로그램 실행에 대해 공부해 보겠습니다. 하나하나 세세하게 설명하기 보다는 컴퓨터 시스템이 어떻게 동작하는지, 여러 프로그램들이 하드웨어 위에서 어떻게 동작하는지에 대해 집중해 보겠습니다.

 


컴퓨터 시스템

위의 사진은 컴퓨터 시스템의 하드웨어 구조는 간략하게 요악한 것입니다. CPU와 Memory로 구성된 것을 보통 컴퓨터 라고 하며 I/O device의 데이터가 컴퓨터로 들어가는 것은 Input이라고 하며 데이터를 받아 CPU에서 처리 후 다시 I/O device로 나가는 것을 Output이라고 합니다. 

 

위의 사진을 좀 더 자세히 보면 아래와 같이 설명할 수 있습니다.

먼저 Memory는 CPU의 작업공간이며 CPU는 매 clock cycle마다 memory의 instruction(기계어)를 읽어 실행합니다. 여기서 instruction은 PC(Program Counter)에 저장되어 있습니다. 사실상 PC에 저장되는 값은 메모리 상의 주소값이죠. CPU는 이 주소에 저장되어 있는 instruction을 실행하며 평생 PC의 값을 읽고 실행하고 읽고 실행하고...이것만 합니다.

 

CPU에는 PC의 값을 읽을 때 마다 Interrupt line이 setting되어 있는지 검사하는데, 만약 set인 경우 인터럽트가 있는 경우로 인터럽트를 처리하며 그렇지 않은 경우 다음 instruction을 수행합니다. 

 

mode bit는 CPU를 사용자 프로세스가 가지고 있는지 운영체제가 가지고 있는지 표시하기 위해 사용합니다. 0인 경우는 커널모드(OS코드 수행)이며 1인 경우는 사용자모드(사용자 프로그램 수행)을 의미합니다. 이렇게 구분한 이유는 사용자 프로그램이 잘못된 수행으로 시스템에 치명적인 피해를 주지 않게 하기 위함입니다. 여기서 좀 더 설명하면, 32bit 기준으로 각각의 프로세스는 4GB의 가상공간을 사용할 수 있는데 2GB는 커널공간, 2GB는 사용자 공간(프로그램)으로 나누어 집니다. 커널모드인 경우 커널, 사용자 공간 모두 접근할 수 있지만 사용자 모드는 사용자 공간만 접근할 수 있습니다.

 

그리고 timer라는 하드웨어 장치가 있는데, CPU의 제어권이 A프로세스에서 B프로세스로 이양될 때 timer에 어떤 값을 세팅합니다. 그렇게 되면 B프로세스는 timer에 세팅된 시간만큼만 프로세스를 사용할 수 있으며 이 시간이 지난 뒤에는 interrupt line을 set하여  C프로세스에게 CPU를 넘겨주게 됩니다. 마찬가지로 timer에 값을 세팅해서 넘겨줍니다.

 

그렇다면 만약 C프로세스가 디스크의 데이터가 필요하면 어떻게 할까요 ? 이런 경우 C프로세스는 CPU를 운영체제 에게 넘겨주고, CPU는 디스크의 데이터를 직접 읽는 것이 아니라 device controller에게 시킵니다. 여기서 CPU는 일을 맡기고 또 다른 작업을 합니다.

 

device controller에는 각 I/O 장치마다 달린 CPU이며 디스크 내부의 헤더가 어떻게 움직이고 어떤 데이터를 읽을지 내부를 통제합니다. 데이터는 local buffer에 저장되며 이후 device controller는 CPU에게 interrupt를 겁니다. 이후 CPU는 디스크의 데이터를 해당 프로세스의 메모리 공간에 copy해 줍니다.

 

사실 조금 있다 나오겠지만 local buffer의 데이터를 프로세스로 copy하는 일은 CPU가 직접하는 것이 아니라 DMA라는 녀석이 합니다.

 

※ 시스템 콜(system call)

32bit 기준으로 각 프로세스는 4GB 공간을 가지며 4GB는 사용자/커널 공간으로 나누어 집니다. 만약 어떤 코드에서 분기, 함수를 호출하면 다른 주소공간으로 jump를 하겠죠. 근데 jump해도 어쨋든 사용자 공간입니다(mode bit 1). 하지만 만약 I/O요청(화면에 출력, 키보드 입력받기)해야 하는 코드를 실행하면 사용자 프로세스는 이를 직접하지 못합니다. CPU제어권을 운영체제 에게 넘겨 대신 I/O작업을 해달라고 부탁합니다(mode bit 0). 이를 system call이라고 합니다. 

 사용자 프로세스는 interrupt line을 set하고, CPU는 PC를 확인하기 전 interrupt line을 검사하는데 set 되어 있는 것을 확인하고 인터럽트 벡터 테이블에서 수행해야 할 작업을 찾은 후 커널 공간으로 jump하여 I/O 작업을 수행합니다.


동기식 입출력과 비동기식 입출력

동기식 입출력(synchronous I/O)

I/O 요청 후 입출력 작업이 완료된 후에야 제어가 사용자 프로그램에게 넘어가게 되며 구현 방법으로는 2가지가 있습니다.

  1. I/O가 끝날 때까지 CPU를 낭비시킴, 매시점 하나의 I/O만 일어날 수 있음
  2. I/O가 와료될 때 까지 해당 프로그램에게서 CPU를 빼앗음, I/O 처리를 기다리는 줄에 그 프로그램을 줄을 세움, 다른 프로그램에게 CPU를 이양함

비동기식 입출력(asynchronous I/O)

I/O가 시작된 후 입출력 작업이 끝나기를 기다리지 않고 제어가 사용자 프로그램에 즉시 넘어갑니다.

 

ㅡ> 두 경우 모두 I/O 완료는 인터럽트로 알려 줍니다.


DMA(Direct Memory Access)

 

위에서 키보드로부터 입력을 받거나, 디스크의 데이터를 읽어 오는 경우 device controller는 그 내용을 읽어 local buffer에 저장후 CPU에 인터럽트를 날린다고 했습니다.

 

근데 만약의 여러 I/O 장치들이 CPU에게 매번 인터럽트를 걸면 CPU가 일을 하는데 비효율 적이지 않을까요 ? 이런 이유로 DMA가 등장하게 됩니다. DMA는 CPU가 I/O가 읽은 데이터를 해당 프로세스의 메모리 공간에 copy해주는 일을 대신해 줍니다. 그리고 DMA는 CPU에게 인터럽트를 걸어 "제가 local buffer에 있는 데이터를 프로세스에 다 옮겨놨습니다"라고 인터럽트로  보고만 해주는 거죠. 

 

사실 원래 memory에 접근할 수 있는 건 CPU만 가능한데 DMA까지 접근하게 되니 충돌할 수가 있습니다. 이런 부분을 통제하는 것이 memory controller입니다.


프로그램의 실행(메모리 load)

결국에 디스크에 존재하는 프로그램을 실행시키기 위해서는 디스크의 프로그램을 메모리에 올려 CPU를 할당받아야합니다. 이렇게 CPU를 할당받을 수 있는 상태를 프로세스라고 합니다. 프로세스는 바로 물리 메모리에 올라가는 것이 아니라, 독자적으로 Virtual Memory라는 가상 주소공간을 가집니다. 

 

가상주소공간은 시스템마다 다르지만 32bit 기준으로 4GB의 크기를 가지며 각각의 프로세스가 물리 메모리와 상관없이 마치 혼자서 4GB를 모두 사용할 수 있는 것 같은 환상을 가지게 합니다(실제로는 4GB에서 커널 공간을 제외한 영역). 가상 주소공간은 각각 code, stack, data, heap 영역으로 나뉘게 됩니다.

 

각 프로세스의 가상 주소공간에서 실제로 프로그램을 실행하는데 필요한 부분은 block단위로 물리 메모리에 올라가게 됩니다. 굳이 현재 실행되는데 필요한 부분은 물리 메모리에 올리지 않는 거죠.  만약 물리 메모리에 block을 올릴 수 있는 자리가 부족하게 되면 swap area라는 디스크영역에 block을 잠시 보관합니다. 여기서 각 프로세스 가상주소 공간의 block을 물리 메모리로 올리는데 주소를 변환하여 올리는데 이를 관리하는 하드웨어 장치가 따로 있습니다.

 

이렇게 디스크에 존재하는 프로그램은 각각의 가상 주소공간을 가지며 실제로 필요한 부분만 물리 메모리에 올라가 CPU를 할당받고, 경우에 따라 swap area에 잠시 보관되기도 합니다. 

 

※ 사진의 file system와 swap area는 모두 하드 디스크이지만 file system의 경우 전원이 나가도 file은 유지되지만 swap area의 경우 전원이 나가게 되면 프로세스도 종류될 뿐만 아니라 memory의 내용도 모두 날아가기 때문에 swap area의 내용도 모두 지워지게 됩니다.