프로그램의 구조와 실행🏃🏻

DEVJUN·2022년 7월 17일
0

운영체제(OS)

목록 보기
3/5
post-thumbnail

1. 프로그램의 구조와 인터럽트

  프로그램이 CPU에서 명령을 수행하려면 해당 명령을 담은 프로그램의 주소 영역이 메모리에 올라가 있어야 한다. 프로그램의 주소 영역은 크게 코드(code), 데이터(data), 스택(stack) 힙(heap) 영역으로 구분된다.

  코드영역은 우리가 작성한 프로그램 함수들의 코드가 CPU에서 수행할 수 있는 기계어 명령 형태로 변환되어 저장되는 부분이고, 데이터 영역은 전역 변수(global variable)등 프로그램이 사용하는 데이터를 저장하는 부분이고, 스택영역은 함수가 호출될 때 호출된 함수의 수행을 마치고 복귀할 주소 및 데이터를 임시로 저장하는 데에 사용되는 공간이다 마지막으로 힙 영역은 프로그래머가 직접 공간을 할당, 해제하는 메모리 공간이다.

  프로그램은 X함수에서 Y함수를 호출한 지점을 스택에 저장해 놓았다가 Y함수가 수행된 후 스택에 저장된 주소 위치로 돌아와 코드를 계속 수행한다. 즉 함수가 호출되면 다음에 실행할 명령의 메모리 위치가 바뀌게 되는 것인데 이는 CPU가 명령을 순차적으로 수행하다가 호출된 함수의 위치로 점프해서 새로운 위치의 명령을 실행 하기 때문이다. 호출된 함수를 모두 수행하고 나면 원래 함수가 수행되던 위치로 돌아가는데 이땐 스택에 저장되어 있는 복귀 주소를 사용한다.

  인터럽트의 동작 원리도 함수의 호출과 비슷하다. A라는 프로그램이 CPU를 할당받고 명령을 수행하고 있는데 인터럽트가 발생하면 A는 수행 중인 명령의 위치를 저장해놓고 운영체제 내부 코드인 인터럽트 처리루틴으로 넘어가서 인터럽트 처리를 하고 다시 돌아와 A의 이전 작업 지점부터 수행을 계속 이어가게 된다. 그런데 다른점은 함수호출에 필요한 복귀 주소는 스택에 저장되지만, 인터럽트 때문에 CPU를 빼앗긴 위치는 운영체제가 관리하는 프로세스 제어블록(PCB)에 저장된다.

2. 컴퓨터 시스템의 작동 개요

  CPU는 빠른 속도로 처리하는 계산 능력은 가지고 있지만, 어떠한 작업을 수행해야 하는지 스스로 결정하는 능력은 갖추고 있지 않다. CPU는 매 시점 메모리의 특정 주소에 존재하는 명령을 하나씩 읽어와 그대로 실행한다. 이때 CPU가 수행해야 할 메모리 주소를 담고 있는 레지스터를 프로그램 카운터(Program Counter: PC)라고 부른다.

  컴퓨터 시스템을 구성하느 하드웨어로는 CPU메모리가 있고, 각 입출력 장치와 이들 장치를 전담하는 작은 CPU인 입출력 컨트롤러와, 이 입출력을 기억하는 메모리인 로컬 버퍼가 있다.

  메모리에는 사용자 프로그램들과 운영체제가 같이 올라가 수행된다. CPU는 프로그램 카운터가 가르키는 메모리 위치의 프로그램을 수행한다. 예를 들어 프로그램 카운터가 메모리 주소 중 운영체제가 존재하는 부분을 가르키고 있다면 현재 운영체제의 코드를 수행 중이며, 이 경우 CPU가 커널모드에서 수행 중이다. 반대로 사용자 프로그램이 존재하는 메모리를 가르킨다면 이는 사용자 모드에서 CPU가 수행되고 있다고 이야기 한다.

  CPU가 수행하는 명령에는 일반명령과 특권명령이 있다. 일반명령은 모든 프로그램이 수행할 수 있는 명령이고, 특권명령은 보안이 필요한 명령으로 입출력 장치, 타이머 등 각종 장치에 접근하는 명령이다.

  사용자 프로그램이 실행되다 보면 일반명령 외에 특권 명령이 수행이 필요한 경우가 있는데 이 경우 사용자 프로그램은 스스로 특권명령을 실행할 수 없으므로 운영체제에게 시스템 콜을 통해 특권명령을 대행 요청한다.

3. 프로그램의 실행

  '프로그램이 실행되고 있다'는 것은 컴퓨터 시스템 차원에서 볼 때 크게 두 가지 중요한 의미를 가진다. 첫 번째는 디스크에 존재하던 실행파일이 메모리에 적재된다는 의미이고, 두 번째는 프로그램이 CPU를 할당받고 명령을 수행하고 있는 상태라는 의미이다.

  프로세스의 주소 공간은 위에서 본 대로 코드(code), 데이터(data), 스택(stack), 힙(heap)등으로 구성된다. 각각의 프로그램마다 이러한 주소 공간을 별도로 가지며, 프로그램마다 독자적으로 존재하는 이와 같은 주소 공간을 가상메모리(virtual memory) 또는 논리적 메모리(logical memory)라고 부른다.

  운영체제도 하나의 프로그램이므로 운영체제 커널 역시 코드, 데이터, 스택의 주소 공간 구성을 가지고 있다.

  커널의 데이터 영역에는 각종 자원을 관리하기 위한 자료구조가 저장된다. CPU나 메모리와 같은 하드웨어 자원을 관리하기 위한 자료구조뿐 아니라 현재 수행 중인 프로그램을 관리하기 위한 자료구조도 커널의 데이터 영역에 유지된다.

  이 때 현재 수행 중인 프로그램을 프로세스(process)라고 부르고, 커널의 데이터 영역 내에는 각 프로세스의 상태, CPU 사용 정보, 메모리 사용 정보 등을 유지하기 위한 자료구조인 PCB를 두고 있다.

  커널의 스택은 일반 사용자 프로그램의 스택과 달리 현재 수행 중인 프로세스마다 별도의 스택을 두어 관리한다. 이는 프로세스가 함수를 호출할 때 자기 주소 영역 내부에 정의된 함수를 호출하면 자신의 스택에 복귀 주소를 저장하지만, 프로세스가 특권명령을 수행하려고 커널에 정의된 시스템 콜을 호출하고 시스템 콜 내부에서 다른 함수를 호출하는 경우 그 복귀 주소는 커널 내의 주소가 되어 사용자 프로그램의 스택과는 별도의 저장공간이 필요하게 되기 때문이다.

4. 사용자 프로그램이 사용하는 함수

프로그램이 사용하는 함수는 사용자 정의함수와 라이브러리 함수, 커널함수 이 세가지로 구분할 수 있다. 사용자 정의함수는 프로그래머가 직접 작성한 함수이고, 라이브러리 함수는 프로그래머 본인이 작성하지는 않았지만 이미 누군가 작성해놓은 함수이고, 커널함수는 운영체제 커널의 코드에 정의된 함수를 뜻한다.

  커널함수의 종류에는 사용자 프로그램이 운영체제의 서비스를 요청하기 위해 호출하는 시스템 콜 함수와, 각종 하드웨어 및 소프트웨어가 CPU의 서비스를 요청하기 위해 발생시키는 인터럽트 처리 함수가 있다.

  예를 들어 화면에 문자열을 출력하는 printf()함수는 그 자체로는 라이브러리 함수이지만 궁극적으로 특권명령인 입출력을 수반하므로 printf()내에서 커널함수를 호출하는 시스템 콜을 동반하게 된다.

5. 인터럽트

  이전 챕터에서 인터럽트에 대해서 알아보았는데 인터럽트 처리 중에 또 다른 인터럽트가 발생하는 경우에는 어떻게 될까?..

 원칙적으로는 인터럽트 처리 중에 또 다른 인터럽트가 발생하는 것은 허용하지 않는다. 이유는 인터럽트 처리 중에 다른 인터럽트를 처리하면 데이터의 일관성이 유지되지 않는 문제가 발생할 수 있기 때문이다.

  그러나 예외가 존재할 수 있다. 예를 들어 인터럽트가 발생해 현재 인터럽트를 수행하고 있지만 그보다 더 시급하거나 CPU를 당장 사용해야 하는 일이 발생할 수 있다.

  이렇게 현재 처리 중인 인터럽트보다 더 높은 우선순위의 인터럽트가 발생하면 현재 처리 중이던 인터럽트 코드의 수행 지점을 저장하고 우선순위가 높은 인터럽트를 처리하게 된다. 인터럽트 처리가 끝나면 저장된 주소로 복귀해 이전에 수행하던 인터럽트 처리 코드를 마저 수행하게 된다.

profile
🧑🏻‍💻iOS

0개의 댓글