:프로그램이 CPU에서 명령을 수행하려면 해당 명령을 담은 프로그램의 주소 영역이 메모리에 올라가 있어야 한다. 프로그램의 주소 영역은 코드(code), 데이터(data), 스택(stack) 3 가지 영역으로 구분된다.
코드 영역 : 작성한 함수들의 코드가 CPU에서 수행할 수 있는 기게어 명령(machine instruction) 형태로 변환되어 저장되는 부분.
데이터 영역 : 전역 변수(global variable) 등 프로그램이 사용하는 데이터를 저장하는 부분
스택 영역 : 함수가 호출될 때 호출된 함수의 수행을 마치고 복귀할 주소 및 데이터를 임시로 저장하는 데에 사용되는 공간.
인터럽트 동작 원리
A 라는 프로그램이 CPU를 할당받고 명령을 수행하고 있는데, 인터럽트가 발생하면 A는 현재 수행 중인 명령의 위치를 저장한다.
그 후 운영체제 내부 코드인 인터럽트 처리 루틴으로 넘어가서 인터럽트 처리를 하고 다시 돌아와 A의 이전 작업 지점부터 수행을 이어간다.
일반적으로 프로그램 내에서 발행되는 함수호출에 필요한 복귀 주소는 각 프로그램의 주소 공간 중 스택 영역에 보관한다. 반면 인터럽트 때문에 CPU를 빼앗긴 위치는 운영체제가 관리하는 프로세스 제어블록에 저장된다.
프로세스 제어블록에는 인터럽트가 발생한 시점에 그 프로그램의 어느 부분까지 수행했는지를 저장하며, 인터럽트 처리 후 프로세스 제어블록에 저장된 주소를 복원시켜 원래 수행하던 일을 재개하게 된다.
: CPU는 매 시점 메모리의 특정 주소에 존재하는 명령을 하나씩 읽어와 그대로 실행한다. 이때 CPU가 수행해야 할 메모리 주소를 담고 있는 레지스터를 프로그램 카운터(PC) 라고 부른다. 즉, CPU는 매번 프로그램 카운터가 가리키는 메모리 위치의 명령을 처리하게 된다. 또한 컴퓨터 시스템 동작이 CPU 에서만 이루어 지는게 아니라 디스크 파일을 읽어오는 등 외부장치를 통해 동작할 수 있으므로 총체적은 이해가 필요하다.
먼저 컴퓨터 시스템을 구성하는 하드웨어로는 CPU와 메모리가 있다. 입출력 장치를 전달하는 작은 CPU와 출력 컨트롤러와 로컬 버퍼라고 부른다.
메모리에는 사용자 프로그램과 운영체제가 같이 올라가 수행된다. 이때 CPU는 프로그램 카운터가 가리키는 메모리 위치의 프로그램을 수행한다.
CPU 가 수행하는 명령에는 일반 명령 과 특권 명령 이 있다.
일반 명령 :
메모리에서 자료를 읽어와 CPU에서 계산하고 결과를 메모리에 쓰는 일련의 명령이고, 모든 프로그램에서 수행할 수 있는 명령이다.
특권명령 :
보안이 필요한 명령으로 입출력 장치, 타이머 등 각종 장치에 접근하는 명령이다. (특권 명령은 항상 운영체제만이 수행할 수 있도록 제한하고 있다.)
📌 사용자 모드에서 특권명령이 필요한 경우(디스크 파일 접근, 수행결과 화면 출력 등) 에는 운영체제에게 특권명령의 대행을 요청한다.
이와 같은 서비스 요청을 시스템 콜 이라고 한다.
: 프로그램이 실행되고 있다는 것은 시스템 차원에서 크게 두 가지 중요한 의미를 가진다.
디스크에 존재하던 실행파일이 메모리에 적재된다는 의미.
: 실행파일이 메모리에 적재될 때, 실행파일 전체가 메모리에 한꺼번에 올라가기보다는 일부분만 메모리에 올라가고 나머지는 디스크의 특정 영역에 내려가는 것이 일반적인데, 이는 여러 프로그램이 함께 사용하는 메모리 공간을 더 효율적으로 사용하기 위한 방법.
프로그램이 CPU 를 할당받고 명령(instruction) 을 수행하고 있는 상태라는 의미.
: 일반적인 컴퓨터 시스템의 경우 CPU 는 하나밖에 없으므로 매 시점 CPU 에서 명령을 수행하는 프로그램은 하나 뿐이다. 하지만 여러 프로그램이 짧은 시간 단위로 CPU 를 나누어 쓰고, 이들 프로그램이 메모리에 동시에 적재되어 있을 수 있으므로 여러 프로그램이 동시에 실행된다는 말을 보편적으로 사용하는 것이다.
프로세스 주소 공간
: 코드, 데이터, 스택 등으로 구성되어 있는데, 각각의 프로그램마다 이러한 주소 공간을 별도로 가지며, 프로그램마다 독자적으로 존재하는 이와 같은 주소 공간을 우리는 가상 메모리 (virtual memory) 또는 논리적 메모리 (logical memory) 라고 부른다.
운영 체제의 커널
: 마찬가지로 코드, 데이터, 스택의 주소 공간 구성을 가지고 있다.
커널 코드는 CPU, 메모리 등의 자원을 관리하기 위한 부분과 사용자에게 편리한 인터페이스를 제공하기 위한 부분이 주를 이루고 있다. 이 밖에도 커널의 코드는 시스템 콜 및 인터럽트를 처리하기 위한 부분을 포함한다.
커널 데이터 영역에는 각종 자원을 관리하기 위한 자료구조가 저장된다. 각 프로세스의 상태, CPU 사용 정보, 메모리 사용 정보 등을 유지하기 위한 자료구조인 *PCB 를 두고 있다. 이와 같이 커널의 데이터 영역에는 하드웨어와 소프트웨어를 포함하는 시스템 내의 모든 자원을 관리하기 위한 자료구조를 각각 유지한고 있다.
커털 스택 영역은 일반 프로그램의 스택 영역과 마찬가지로 함수호출 시의 복귀 주소를 저장하기 위한 용도로 사용된다. 하지만 커널의 스택은 일반 사용자 프로그램의 스택과 달리 현재 수행 중인 프로세스마다 별도의 스택을 두어 관리한다.
이는 프로세스가 함수를 호출할 때 자기 주소 영역 내부에 정의된 함수를 호출하면 자신의 스택에 복귀 주소를 저장하지만, 프로세스가 특권 명령을 수행하려고 커널에 정의된 시스템 콜을 호풀하고 시스템 콜 내부에서 다른 함수를 호출하는 경우 그 복귀 주소는 커널 내의 주소가 되어 사용자 프로그램의 스캣과는 별도의 저장공간이 필요하게 되기 때문이다.
💡 PCB 란 ?
: 프로세스 제어 블록(Process Control Block, 줄여서 PCB)은 특정한 프로세스를 관리할 필요가 있는 정보를 포함하는, 운영체제 커널의 자료구조
:프로그램이 사용하는 함수는 크게 3가지로 사용자 정의함수, 라이브러리 함수, 커널함수 이다.
라이브러리 함수 : 프로그래머 본인이 직접 작성하지는 않았지만 이미 누군가 작성해놓은 함수를 호출를 호출만 하여 사용하는 경우
사용자 정의함수 : 사용자가 직접 작성해 함수를 호출하는 경우인데, 사용자 정의함수와 라이브러리 함수는 모두 그 프로그램의 코드 영역에 기계어 명령 현태로 존재한다. 따라서 이 두 함수는 프로그램이 실행될 때에 해당 프로세스의 주소 공간에 포함되면, 또한 함수호출 시에도 자신의 주소 공간에 있는 스택을 사용하게 된다.
커널 함수 : 운영체제 커널의 코드에 정의된 함수를 뜻하며, 커널함수의 종류에는 사용자 프로그램이 운영체제의 서비스를 요청하기 위해 호출하는 시스템 콜 함수와 각종 하드웨어 및 소프트웨어가 CPU 의 서비스를 요청하기 위해 발생시키는 입터럽트 처리 함수가 있다.
: CPU의 정상작동을 방해하는 행위로 CPU 는 일반적으로 프로그램 카운터가 가리키는 곳에 있는 명령을 수행하지 않기 때문에, 현재 수행 중인 프로세스로부터 CPU를 회수해 CPU가 다른 일을 수행하도록 하기 위해서는 인터럽트 메커니즘이 필요하다.
CPU는 매번 프로그램 카운터가 가리키고 있는 지점의 명령을 하나씩 수행하고 나서, 다음 명령을 수행하기 직전에 인터럽트 라인이 세팅되었는지 체크한다.
인터럽트 라인 체크를 통해 인터럽트가 발생 했으면 CPU는 현재 수행하던 프로세스를 멈추고 운영체제의 인터럽트 처리 루틴으로 이동해서 인터럽트 처리를 수행한다.
인터럽트의 처리를 마치고 나면 인터럽트가 발생하기 직전의 프로세스에게 CPU의 제어권이 다시 넘어가게 된다.
원칙적으로는 인터럽트 처리 중에 또 다른 인터럽트가 발생하는 것을 허용하지 않는다.
그 이유는 인터럽트 처리 중에 다른 인터럽트를 처리하면 데이터의 일관성이 유지되지 않는 문제가 발생할 수 있기 때문인데, 경우에 따라 예외가 존재할 필요성이 있다. 예를 들어 인터럽트가 발생해 현재 인터럽트 처리루틴을 수행하고 있지만, 그보다 더 시급하거나 CPU를 당장 사용해야 하는 일이 발생할 수 있기 때문이다. 그렇기 때문에 상대적으로 낮은 중요도를 가진 인터럽트를 처리하는 도중에 중요도가 더 높은 인터럽트가 발생하는 것을 허락할 필요가 있다. 이와 같이 현재 처리 중인 인터럽트보다 더 높은 우선순위의 인터럽트가 발생한다면 현재 처리 중이던 인터럽트 코드의 수행 지점을 저장하고 우선순위가 높은 인터럽트를 처리하게 된다.
💡 인터럽트 라인이란 ?
: CPU 가 명령을 수행하면서 인터럽트가 있는지 확인하는 공간.
CPU 가 빠른 속도로 작업을 수행하면서 주기적으로 추가된 인터럽트가 있는지 확인한다.
: 일반적인 함수 호출이 자신의 스택에 복귀 주소를 저장한 후 호출된 함수 위치로 점프하는 것임에 비해, 시스템 콜은 주소 공간 자체가 다른 곳으로 이동해야 하므로 일반 함수호출과는 상이한 방법을 사용한다.
CPU가 디스크 컨트롤러에게 데이터를 읽어오라는 명령을 내린다.
디스크 컨트롤러는 디스크로부터 데이터를 읽어와서 로컬버퍼에 저장한다.
이 작업이 완료되면 디스크 컨트롤러가 CPU에 인터럽트를 발생시켜 입출력 작업이 완료 되었음을 통지한다.
CPU 는 프로그램 카운터가 가리키는 메모리 위치의 명령만 계속 수행하기 때문에 주변장치의 상태를 지속적으로 파악할 수 없다.
따라서 주변장치는 CPU의 도움이 필요한 경우 인터럽트를 사용해 CPU 에게 서비스를 요청한다.
인터럽트를 발생시키기 위해 주변 장치는 *인터럽트 라인 을 세팅하고 CPU는 매번 명령을 수행한 직후 인터럽트 라인을 체크해 서비스 요청이 들어왔는지 확인한다.
이때 인터럽트 의 종류는 다양하기 때문에 각각의 인터럽트 발생 원인마다 라인을 다르게 해서 구분하게 된다.
인터럽트가 발생하면 CPU 는 해당 인터럽트를 처리하기 위한 루틴으로 넘어가서 커널 내의 인터럽트 처리 코드를 수행한다.
: 사용자모드와 커널모드
사용자 모드 :자신의 주소 공간에 정의된 코드를 실행하는 것
커널모드 : 커널의 시스템 콜 함수를 실행하는 것 시스템 콜을 통해 실행되는 것이 프로세스 A의 코드가 아닌 운영체제 커널의 코드이지만, 시스템 콜이 수행되는 동안 커널이 실행 상태에 있다고 하지 않고 프로세스 A의 코드가 실행 상태에 있다고 말한다.