현재 포스팅은 반효경 교수님의 운영체제 강의 + 추가적인 내용을 바탕으로 정리된 글입니다 :)
1. 프로그램 구조와 인터럽트
프로그램이 CPU에서 명령을 수행하려면, 주소 영역이 메모리에 올라가 있어야 하는데, 이러한 주소 영역은 크게 코드, 데이터, 스택 영역으로 구분되어있습니다.
코드 영역에는 우리가 작성한 프로그램 코드들이 CPU에서 수행할 수 있는 기계어 형태로 변환되어 저장되고, 데이터 영역에는 전역 변수 등 프로그램이 사용하는 데이터들이 저장되어있습니다. 그리고 스택 영역은 함수가 호출될 때 호출된 함수의 수행을 마치고 복귀 주소 및 데이터를 임시로 저장하는 데에 사용하는 공간입니다.
인터럽트 동작 원리는 함수 호출과 비슷하지만, 복귀 주소가 어디에 저장되는지에 차이를 보입니다.
일반적으로 프로그램 내에서 발생하는 함수호출에 필요한 복귀 주소는 각 프로그램의 주소 공간 중 스택 영역에 저장되는 반면, 인터럽트 때문에 CPU를 빼앗긴 위치는 운영체제가 관리하는 프로세스 제어 블록(PCB)에 저장됩니다.
2. 컴퓨터 시스템의 작동 개요
보통 CPU를 컴퓨터 내의 두뇌라고 하는데, 이러한 CPU는 스스로 어떤 일을 해야할지 결정을 할 수 있을까요?
CPU는 어떠한 작업을 해야할 지 스스로 결정하는 능력이 없습니다. 단지 매 시점 특정 주소에 존재하는 명령을 하나씩 가져와 실행할 뿐이죠.
CPU가 수행해야할 메모리 주소를 담고 있는 레지스터를 PC(Program Counter)라고 부르며, CPU는 PC가 가리키고 있는 주소에 있는 명령을 수행합니다.
CPU가 수행하는 명령어에는 일반 명령과 특권 명령이 있습니다.
일반명령은 메모리에서 자료를 읽어와 CPU에서 계산하고 결과를 메모리에 쓰는 일련의 명령들을 말하며, 이러한 일반명령은 모든 프로그램이 수행할 수 있는 명령입니다.
반면 특권명령은 보안이 필요한 명령으로, 입출력 장치나 타이머 등 각종 장치에 접근하는 명령입니다. 컴퓨터 시스템에서 이러한 특권 명령은 항상 운영체제만이 수행할 수 있도록 제한하고 있습니다.
컴퓨터 시스템은 이러한 명령의 실행 가능성을 체크하기 위해 CPU 내에 모드 비트를 두는데, 이에 대한 상세한 설명은 앞선 2강의 포스팅을 참고해주세요!
사용자 프로그램이 실행되다 보면, 일반 명령 외에 특권 명령의 수행이 필요한 경우가 있습니다. 예를 들어 디스크의 파일에 접근하거나, 수행 결과를 화면의 출력하는 등의 작업은 특권 명령의 수행을 필요로 합니다. 이럴때 운영체제에게 특권 명령의 대행을 요청하게 되는데, 이를 시스템 콜이라고 합니다.
사용자 프로그램이 시스템 콜을 하게 되면, 운영체제는 사용자 프로그램의 코드가 아닌 자신의 커널 영역에 정의된 시스템 콜 처리코드를 수행하게 됩니다.
3. 프로그램의 실행
프로그램의 실행이라는 말은 컴퓨터 시스템 차원에서 크게 두가지 중요한 의미를 가집니다.
첫번째는 디스크에 존재하던 실행파일이 메모리에 적재된다는 의미이고, 두번쨰는 프로그램이 CPU를 할당받고 명령(instruction)을 수행하고 있는 상태라는 의미입니다.
프로그램의 주소 공간은 앞서 설명드린 대로 코드, 데이터, 스택 등으로 구성됩니다.
각각의 프로그램 마다 이러한 주소 공간을 별도로 가지며, 각 프로그램마다 독자적으로 존재하는 이와 같은 주소공간을 우리는 가상 메모리(virtual Memory) 또는 논리적 메모리(logical Memory)라고 부릅니다.
운영체제 또한 하나의 프로그램이기에, 커널 역시 코드,데이터,스택의 주소 공간을 가지고 있습니다.
커널의 코드 영역에는 CPU,Memory 등 자원을 관리하기 위한 코드, 사용자에게 편리한 인터페이스를 제공하기 위한 코드들이 저장되어있습니다. 이 밖에도 시스템 콜 및 인터럽트 처리를 위한 코드 또한 포함하고 있습니다.
커널의 데이터 영역에는 각종 자원을 관리하기 위한 자료구조가 저장되어있습니다.
이러한 데이터영역에는 프로세스의 상태, CPU 사용 정보, 메모리 사용 정보 등을 유지하기 위한 자료구조인 PCB가 포함되어있습니다.
커널의 스택 영역에는 일반 프로그램의 스택 영역과 마찬가지로 함수 호출시 복귀 주소를 저장하기 위한 용도로 사용됩니다.
하지만 커널의 스택은 일반 사용자 프로그램의 스택 영역과 달리 현재 수행 중인 프로세스마다 별도로 스택을 두어 관리합니다.
이는 프로세스가 함수를 호출할때 자신 주소 영역 내부에 정의된 함수를 호출(사용자 모드)하면 자신의 스택에 복귀 주소를 저장하지만, 프로세스가 특권 명령을 수행(커널모드)하려고 커널의 정의된 시스템 콜을 호출하고 시스템 콜 내부에서 다른 함수를 호출하는 경우, 그 복귀주소는 커널 내의 주소가 되어 사용자 프로그램의 스택과는 별도의 저장공간이 필요하기 떄문입니다.
정리하자면 프로그램이 자기 자신의 코드 내에서 함수 호출 및 복귀 주소를 유지하기 위해서는 자기 주소 공간 내의 스택을 사용하고, 시스템 콜이나 인터럽트등으로 운영체제의 코드가 실행되는 중에 함수호출이 발생할 경우 커널 스택을 사용하게 되는 것입니다.
이때 한가지 유의해야 할 점이 있습니다. 프로그램 내의 함수 호출 시 해당 프로그램의 스택에 복귀 주소를 저장하지만, 시스템 콜이나 인터럽트 발생으로 CPU의 수행 주체가 운영체제로 바뀌는 순간에는 직전에 수행되던 프로그램의 복귀 정보를 스택이 아닌 PCB에 저장한다는 점입니다!
4. 사용자 프로그램이 사용하는 함수
프로그램이 사용하는 함수는 크게 사용자 정의 함수, 라이브러리 함수, 커널 함수로 나뉩니다.
사용자 정의 함수란 개발자가 직접 작성한 함수를 뜻하며 라이브러리 함수는 다른 개발자에 의해 작성된 함수로 이를 호출하여 사용하게 됩니다.
이러한 사용자 정의 함수와 라이브러리 함수 모두 그 프로그램의 코드 영역에 기계어 상태로 존재합니다.
즉 두 함수는 프로그램이 실행될 때, 프로그램의 주소 영역에 포함되며, 함수 호출 시에도 자신의 주소 공간에 있는 스택을 사용하게 됩니다.
커널 함수는 운영체제 커널의 코드에 정의된 함수를 뜻합니다. 이러한 커널 함수의 종류로는 사용자 프로그램이 운영체제의 서비스를 요청하기 위한 시스템 콜 함수와, 각종 하드웨어 및 소프트웨어가 CPU의 서비스를 요청하기 위해 발생시키는 인터럽트 처리 함수가 있습니다.
이러한 커널 함수는 사용자 프로그램의 주소 공간에 코드가 존재하는 것이 아니라, 운영체제 커널의 주소 공간에 코드가 정의됩니다. 즉 운영체제 내에 있는 함수를 사용자 프로그램이 호출해서 사용하는 것입니다!
예를들어 삼각함수 sin()과 같은 함수와 달리, 화면에 문자열을 출력(I/O)하는 printf() 함수는 그 자체로는 라이브러리 함수이지만, 궁극적으로는 특권 명령인 입출력을 수반하므로 printf()내에서 커널 함수를 호출하는 시스템 콜을 동반하게 됩니다.
CPU를 운영체제에 넘기기 위해 시스템콜은 인터럽트와 동일한 메커니즘, 즉 CPU의 인터럽트 라인을 세팅하는 방법을 사용한다는 것도 기억해 둡시다 :)
5. 인터럽트
CPU는 프로그램 카운터가 가리키는 곳에 있는 명령을 수행하는 일밖에 하지 않기에, 현재 수행중인 프로세스로 부터 CPU를 회수하여 CPU가 다른 일을 하도록 하려면, 인터럽트 메커니즘이 필요합니다.
일반적으로 CPU가 아닌 다른 하드웨어 장치가 CPU에게 서비스를 요청할 경우, CPU내에 인터럽트 라인을 세팅해서 인터럽트를 발생시킵니다.
이때 CPU는 매번 PC가 가리키는 지점의 명령을 하나씩 수행하고나서 다음 명령을 수행하기 전에 인터럽트 라인이 세팅되었는지 확인하는 과정을 거칩니다.
만약 인터럽트가 발생하였다면 CPU는 현재 수행하던 프로세스를 멈추고 운영체제 인터럽트 처리 루틴으로 이동해 인터럽트를 수행하게 되고, 처리를 마친 후에는 인터럽트가 발생하기 직전의 프로세스에게 CPU 제어권이 넘어갑니다.
그렇다면 만약 인터럽트 처리 중에 또 다른 인터럽트가 발생하는 경우엔 어떻게 해결할까요???
원칙적으로는 데이터의 일관성이 유지되지 않는 문제가 발생할수 있어 인터럽트 처리 중에 또 다른 인터럽트가 발생하는 것을 허용하지 않습니다.
하지만 경우에 따라 예외가 존재할 필요성이 있습니다. 예를 들어 인터럽트가 발생해 현재 인터럽트 처리 루틴을 수행하고 있지만, 그 보다 더 시급하거나 CPU를 당장 사용해야 하는일이 발생할 수 있기 때문입니다.
즉 인터럽트마다 중요도가 다르기에 상대적으로 낮은 중요도를 가진 인터럽트를 처리하는 도중에 중요도가 더 높은 인터럽트가 발생하는 것을 허락할 필요가 있습니다. 이와 같이 현재 처리 중인 인터럽트보다 더 높은 우선순위의 인터럽트가 발생한다면 현재 처리 중이던 인터럽트 코드의 수행 지점을 저장하고 우선순위가 높은 인터럽트를 처리하게 됩니다.
이후 인터럽트 처리가 끝나면 저장된 주소로 복귀해 이전에 수행하던 인터럽트 처리 코드를 마저 수행하게 되겠죠??
6. 시스템 콜
앞서 설명 드렸듯이, 모든 프로그램은 자기 자신의 독자적인 주소 공간을 가지고 있으며, 프로그램이 함수 호출을 하는 경우 자신의 주소 공간 내에서 호출이 이루어지게 됩니다. 하지만 자신의 프로그램이 아닌, 커널이라는 다른 프로그램의 주소 공간에 존재하는 함수를 호출하기 위해서는 시스템 콜을 사용합니다. 이러한 시스템콜은 인터럽트와 마찬가지로 마찬가지로, 인터럽트 라인에 인터럽트를 세팅하는 명령을 통해 이루어집니다.
디스크의 파일 입출력이 이루어지는 과정을 통해 시스템 콜의 사용 예를 알아보겠습니다!
사용자 프로그램이 CPU에서 명령을 수행하던 중 디스크의 파일을 읽어와야 할 경우, 시스템 콜로 커널의 함수를 호출하게 됩니다. 왜냐하면 입출력 함수의 호출이 자신의 주소 공간에서 이루어질수 없기에, 사용자 프로그램은 CPU의 제어권을 운영체제에게 넘겨주어야합니다. 이때 넘겨주는 과정은 인터럽트 라인을 세팅하는 명령을 통해 이루어집니다.
CPU가 앞서 입출력 과정을 위한 인터럽트 라인이 세팅되었다는 것을 인지한다면, 현재 수행 중인 사용자 프로그램을 잠시 멈춘 후 CPU 제어권을 운영체제로 넘겨주게 됩니다. 만약 디스크 컨트롤러가 로컬 버퍼에 데이터 저장을 완료했다는 인터럽트라면, 운영체제에게 CPU 제어권을 넘기는 것이 아닌 CPU가 해당 데이터를 메모리로 옮기는 작업을 진행하겠죠??
CPU 제어권을 운영체제에 넘겨준 후, 해당 서비스 루틴으로 이동해 입출력 작업을 수행하게 됩니다. 이 과정에서 CPU는 디스크 컨트롤러에게 파일을 읽어오라는 명령을 하게 되는 것입니다 :)
대부분의 경우 운영체제는 입출력을 요청한 다음 CPU의 제어권을 다른 프로세스에게 넘겨줍니다. 이때 다른 프로세스가 CPU에서 명령을 수행하던 중 입출력 작업이 완료되면 디스크 컨트롤러가 CPU에게 인터럽트를 발생시켜 요청된 입출력 작업이 완료되었음을 알리게 됩니다. 그러면 CPU는 사용자 프로세스의 수행을 잠시 멈추고 인터럽트 처리루틴으로 그 제어권이 넘어가게 됩니다.
제어권이 넘어 간후, 디스크로부터 로컬버퍼에 읽어온 내용을 컴퓨터 내의 메모리의 복사한 후 디스크 입출력을 요청했던 프로세스에게 다시 CPU를 획득할 수 있는 권한을 주겠죠??(Blocked 상태 해제 인것!)
그러면 해당 프로세스는 CPU를 기다리는 큐에 삽입되고 CPU의 제어권은 다시 인터럽트를 당한 프로세스로 넘어가 하던 작업이 계속 수행됩니다.
지금 까지 살펴본 내용을 통해, 프로그램이 CPU를 할당받아 명령을 수행하는 중간에 CPU를 빼앗기는 경우는 크게 두가지가 있음을 알 수 있습니다.
우선 첫번쨰는 타이머에 의해 인터럽트가 발생하는 경우이고, 다른 하나는 입출력 요청을 위해 시스템 콜을 하는 경우입니다.
7. 프로세스의 두가지 실행 상태
프로세스는 자신의 주소 공간에서 정의된 코드를 실행하는 사용자 모드에서의 실행상태(user mode Running)와 커널의 시스템 콜 함수를 실행하는 커널 모드에서의 실행상태(Kernel Mode Running)로 나뉩니다.
이때 한가지 주의할 점은, 비록 시스템 콜을 통해 호출되는 것이 프로세스 자신의 코드가 아닌 운영체제 커널의 코드이지만, 시스템 콜이 수행되는 동안 커널이 실행상태에 있다고 하지 않고, 프로세스 A가 실행 상태에 있다고 말하는 점입니다.
프로세스 A 입장에서는 CPU를 운영체제 커널에 빼앗긴 것으로 생각할 수도 있지만 커널의 코드가 실행되는 것이 사실상 프로세스가 A가 해야할 일을 대행하는 것이기에 시스템 콜이 실행 중일 때에도 여전히 프로세스 A는 실행상태에 있는 것으로 간주한다는 것입니다.
다만 실행 상태와 구분하여, 프로세스 A가 커널모드에서 실행 중 이라고 이야기 할 수 있습니다.
개발자 준비생이 대학 강의를 듣고 정리한 내용입니다
혹시 틀린 내용이 있다면 댓글 부탁드리겠습니다!! 곧바로 수정하겠습니다
'운영체제 > 반효경 교수님 - 운영체제 강의' 카테고리의 다른 글
운영체제 6강 - 메모리 관리 (1) | 2023.06.09 |
---|---|
운영체제 5강 - CPU 스케쥴링 (0) | 2023.06.08 |
운영체제 4강 - 프로세스 관리 (2) | 2023.06.07 |
운영체제 2강 - 컴퓨터 시스템의 동작 원리 (2) | 2023.06.06 |
운영체제 1강 - 운영체제 개요 (2) | 2023.05.30 |