프로그램은 어떻게 실행되는지, 인터럽트와 시스템 콜은 무엇인지 알아보자.
1. 프로그램의 구조와 인터럽트
프로그램의 주소 영역
프로그램이 CPU에서 명령을 수행하려면 해당 명령을 담은 프로그램의 주소 영역이 메모리에 올라가 있어야 한다.
구성 요소 | 설명 |
---|---|
코드(code) | 프로그램 함수들의 코드가 CPU에서 수행할 수 있는 기계어 명령 형태로 변환되어 저장되는 부분 |
데이터(data) | 전역 변수(global variable) 등 프로그램이 사용하는 데이터를 저장하는 부분 |
스택(stack) | 함수가 호출될 때 호출된 함수의 수행을 마치고 복귀할 주소 및 데이터를 임시로 저장하는 부분 |
함수 호출 vs. 인터럽트: 중단 지점의 주소를 어디에 저장하는가?
구분 | 중단 지점의 주소를 저장하는 곳 |
---|---|
함수 호출 | 프로그램 주소 공간 중 스택 |
인터럽트 | 운영체제가 관리하는 프로세스 제어블록(PCB) |
함수 호출 동작 원리
- CPU는 함수 X의 코드를 수행하다가 다른 함수 Y가 호출되면, 해당 프로그램의 주소 공간 중 스택(stack)에 해당 지점(=복귀 주소)을 저장하고 다음에 실행할 명령의 메모리 위치를 함수 Y로 이동한다.
- 프로그램은 새로운 위치로 이동하여 함수 Y를 실행한다.
- 함수 Y의 수행이 완료되면 스택에 저장된 복귀 주소를 사용하여 원래 호출했던 함수 X 내 위치로 돌아온다.
인터럽트 동작 원리
- 프로그램 A가 CPU를 할당받고 수행 중에 인터럽트가 발생하면 A는 현재 수행 중인 명령의 위치를 운영체제가 관리하는 프로세스 제어블록(PCB)에 저장한다.
- 운영체제 내부 코드인 인터럽트 처리루틴으로 넘어가서 인터럽트를 처리한다.
- 프로세스 제어블록(PCB)에서 프로그램 A의 이전 작업 지점의 주소를 복원하여 수행을 계속 이어간다.
2. 컴퓨터 시스템의 작동 개요
구성 요소 정리
프로세서 | 저장 공간 | |
---|---|---|
컴퓨터 시스템 | CPU | 메모리 |
입출력 장치 | 입출력 컨트롤러 | 로컬 버퍼 |
구분 | 설명 |
---|---|
CPU | PC(프로그램 카운터)가 가리키는 메모리 위치의 프로그램을 수행함 |
메모리 | 사용자 프로그램과 운영체제가 같이 올라가 수행됨 |
프로그램 카운터(Program Counter; PC)
CPU가 수행해야 할 메모리 주소를 담고 있는 레지스터이다.
CPU는 매 시점 PC가 가리키는 메모리 위치의 명령을 하나씩 읽어와 그대로 실행할 뿐이다.
일반적으로 주소 이동이 없는 이상(ex. 조건문, 반복문, 함수호출 등), 프로그램 카운터는 항상 바로 다음 명령을 가리키게 되어 코드가 순차적으로 수행된다.
커널 모드(Kernel Mode) vs. 사용자 모드(User Mode)
CPU의 모드 | 설명 | 모드 비트(mode bit) |
---|---|---|
커널 모드 (kernel mode) | PC(프로그램 카운터)가 메모리 주소 중 운영체제가 존재하는 부분을 가리키고 있어 운영체제의 코드를 수행 중인 상태이다. | 0 |
사용자 모드 (user mode) | PC(프로그램 카운터)가 메모리 주소 중 사용자 프로그램이 존재하는 부분을 가리키고 있어 사용자 프로그램이 수행 중인 상태이다. | 1 |
시스템 콜(System Call)
사용자 프로그램이 실행 중에 특권명령의 수행이 필요할 때, 운영체제에게 시스템 콜(system call)을 통해 특권명령의 대행을 요청한다. 사용자 프로그램이 시스템 콜을 하게 되면 운영체제는 사용자 프로그램의 코드가 아닌 커널 영역에 정의된 시스템 콜 처리 코드를 수행한다.
일반명령
- (1) 메모리에서 자료를 읽어와 (2) CPU에서 계산하고 (3) 결과를 메모리에 쓰는 일련의 명령이다.
- 모든 프로그램이 수행할 수 있다.
특권명령 (Privileged Instructions)
입출력 장치, 타이머 등 각종 장치에 접근하며 보안이 필요한 명령이다.
ex) I/O, 디스크 파일 접근, 모니터 출력
- 운영체제만이 수행할 수 있다.
- CPU 내 모드 비트가
0
일 때, 즉 커널 모드(kernel mode)에서만 수행 가능하다. - 시스템 콜(system call)을 통해 대행을 요청한다.
ex) 디스크에서 데이터를 읽어오는 시스템 콜의 동작 과정
- CPU가 디스크 컨트롤러에게 데이터를 읽어오라는 명령을 내린다.
- 디스크 컨트롤러는 디스크로부터 데이터를 읽어와 로컬버퍼에 저장한다.
- 작업이 완료되면 디스크 컨트롤러가 CPU에 인터럽트를 발생시켜 입출력 작업이 완료되었음을 알린다.
인터럽트(Interrupt) 동작 과정
CPU는 PC가 가리키는 메모리 위치의 명령만을 수행한다. 따라서 주변장치에서 CPU에게 서비스를 요청할 때는 인터럽트를 사용한다.
- 주변장치는 인터럽트 라인(interrupt line)을 셋팅한다.
CPU는 매번 명령을 수행한 직후 인터럽트 라인을 체크하여 서비스 요청이 들어왔는지 확인한다.
인터럽트 발생 원인마다 라인을 다르게 해서 인터럽트의 종류를 구분한다.
- 인터럽트가 발생하면 CPU는 커널 내의 해당 인터럽트 처리루틴으로 넘어가 코드를 수행한다.
System Call & Interrupt
사용자 프로그램이 실행 중에 특권명령을 수행하려면 시스템 콜(system call)을 통해 운영체제에게 특권명령의 대행을 요청한다.
CPU는 커널 모드(kernel mode)로 전환되며, 커널 영역에 정의된 시스템 콜 처리 코드를 수행한다.
해당 작업이 완료되면 CPU에게 인터럽트(interrupt)를 통해 작업이 완료되었음을 알린다.
인터럽트가 발생하면 CPU는 다시 커널 모드(kernel mode)로 전환되며, 커널 영역에 정의된 인터럽트 처리루틴을 수행한다.
3. 프로그램의 실행
용어 정리
- “프로그램이 실행되고 있다”
- 디스크에 존재하던 실행파일이 메모리에 적재된다.
- 프로그램이 CPU를 할당받고 명령을 수행하고 있는 상태이다.
- “여러 프로그램이 동시에 실행된다”
- 매 시점 하나의 CPU에서 명령을 수행하는 프로그램은 하나이지만, 여러 프로그램이 짧은 시간 단위로 CPU를 나누어 쓴다.
- 이들 프로그램이 메모리에 동시에 적재되어 있을 수 있다.
실행 파일이 메모리에 적재되는 과정
- 프로그램의 주소 공간 중 당장 CPU의 수행에 필요한 부분은 메모리에 올리고, 그렇지 않은 부분은 디스크 중 메모리의 연장 공간인 스왑 영역(swap area)에 내려놓는 방식으로 운영된다.
- 가상 메모리(virtual memory; logical memory)
- 실제 물리적 메모리와 독립적으로 각 프로그램마다 가지는 독자적인 주소 공간이다.
- 각각의 프로그램마다 프로세스의 주소 공간(code, data, stack 등)을 별도로 가진다.
- 운영체제 커널(kernel) 또한 주소 공간을 가지고 있다.
커널(Kernel)의 주소 공간 영역
- 코드(code)
- 자원(ex. CPU, 메모리)을 관리하기 위한 부분
- 사용자에게 편리한 인터페이스를 제공하기 위한 부분
- 시스템 콜 및 인터럽트 처리를 위한 부분
- 데이터(data)
- 하드웨어 자원(ex. CPU, 메모리)을 관리하기 위한 자료구조
현재 수행 중인 프로그램(= 프로세스, process)을 관리하기 위한 자료구조 (→ PCB)
프로세스 제어블록 (PCB; Process Control Block)
- 운영체제가 현재 시스템 내에서 실행되는 프로그램들을 관리하기 위해 가지는 자료구조이다.
- 각 프로그램마다 하나씩 존재한다.
- 각 프로세스의 상태, CPU 사용 정보, 메모리 사용 정보 등을 유지한다.
- 스택(stack)
- 커널의 코드가 수행되는 도중에 일어나는 함수 호출 시의 복귀 주소를 저장하기 위한 용도
- 일반 사용자 프로그램의 스택과 달리, 현재 수행 중인 프로세스마다 별도의 스택을 두어 관리
복귀 정보를 저장하는 케이스 📌
복귀 정보를 저장하는 상황 | 복귀 정보 저장 위치 |
---|---|
프로그램이 자기 자신의 코드 내에서 함수호출 및 복귀 주소를 유지할 때 | 프로그램 자신의 주소 공간 내의 스택 |
운영체제의 코드가 실행(ex. 시스템 콜, 인터럽트 등)되는 중에 함수호출이 발생하여 복귀 주소를 유지할 때 | 커널의 주소 공간 내의 스택 - 프로세스마다 별도로 가짐 - 직전에 CPU를 가지고 있던 프로세스의 커널 스택 |
CPU의 수행 주체가 운영체제로 바뀌는 순간(ex. 시스템 콜, 인터럽트 등), 직전에 수행되던 프로그램의 복귀 정보를 저장할 때** | 커널에서 관리하는 프로세스 제어블록(PCB) (데이터 영역) |
4. 사용자 프로그램이 사용하는 함수
- 사용자 정의 함수: 프로그래머 본인이 직접 작성한 함수
- 라이브러리 함수: 이미 누군가 작성해놓은 함수를 호출만 하여 사용하는 경우
- 커널 함수: 운영체제 커널 내에 존재하는 함수
- 시스템 콜 함수: 사용자 프로그램이 운영체제의 서비스를 요청(ex. I/O)하기 위해 호출하는 함수
- 인터럽트 처리 함수: 각종 하드웨어 및 소프트웨어가 CPU의 서비스를 요청하기 위해 발생시키는 함수
위치 | 특징 | |
---|---|---|
사용자 정의 함수, 라이브러리 함수 | 프로세스의 주소 공간 중 코드 영역 | 함수 호출 시 자신의 주소 공간 중 스택 영역을 사용 |
커널 함수 | 운영체제 커널의 주소 공간 중 코드 영역 | 시스템 콜 함수, 인터럽트 처리 함수 |
일반적인 함수 호출 vs. 시스템 콜
일반적인 함수 호출 | 시스템 콜(system call) |
---|---|
사용자 프로그램 내에 존재하는 코드 실행 | 운영체제라는 별개의 프로그램에 CPU를 넘겨서 실행 → 인터럽트와 동일한 메커니즘(= CPU의 인터럽트 라인 셋팅) 사용 → 트랩(trap) |
5. 인터럽트(Interrupt)
CPU는 매번 프로그램 카운터(PC)가 가리키는 곳에 있는 명령을 수행하는 일밖에 하지 않는다. 따라서 현재 수행 중인 프로세스로부터 CPU를 회수해 CPU가 다른 일을 수행하도록 하기 위해서는 인터럽트(interrupt)를 사용해야 한다.
인터럽트 메커니즘
일반적인 메커니즘
- CPU는 매번 PC가 가리키고 있는 지점의 명령을 하나씩 수행하고 나서, 다음 명령을 수행하기 직전에 인터럽트 라인이 셋팅되었는지 확인인다.
인터럽트가 발생했으면, CPU는 현재 수행하던 프로세스를 멈추고 운영체제의 인터럽트 처리루틴으로 이동해서 인터럽트를 처리한다.
→ PCB에 실행 중이던 프로세스의 정보 저장
- 인터럽트 처리를 마치고 나면 인터럽트가 발생하기 직전의 프로세스에게 CPU의 제어권이 다시 넘어간다.
인터럽트 처리 중에 우선순위가 더 높은 다른 인터럽트가 발생하는 경우
- 현재 처리 중이던 인터럽트 코드의 수행 지점을 저장한다.
- 새로 발생한 우선순위가 높은 인터럽트를 처리한다.
- 인터럽트 처리가 끝나면 저장된 주소로 복귀해 이전에 수행하던 인터럽트 처리 코드를 마저 수행한다.
6. 시스템 콜(System Call)
위치 | 실행 방법 | |
---|---|---|
일반적인 함수호출 | 프로그램 자신의 주소 공간 내에서 호출 | 자신의 스택에 복귀 주소 저장 후 호출된 함수 위치로 점프 |
시스템 콜 | 커널이라는 다른 프로그램의 주소 공간에 존재하는 함수 호출 | 프로그램 자신이 스스로 인터럽트 라인에 인터럽트를 셋팅 하는 명령 수행 |
시스템 콜 메커니즘 📌
ex) 디스크의 파일 입출력이 이루어지는 과정
사용자 프로그램이 커널의 함수를 호출하기 위해 시스템 콜(system call)을 발생시키고, 인터럽트 라인을 셋팅하는 명령을 수행한다.
이때 발생한 인터럽트는 소프트웨어 인터럽트이다.
CPU는 다음 명령을 수행하기 전, 인터럽트가 발생한 것을 인지하고 현재 수행 중인 사용자 프로그램을 잠시 멈춘 후 CPU의 제어권을 운영체제로 이양시킨다.
현재 수행 중인 사용자 프로그램의 정보를 PCB에 저장한다.
운영체제는 설정된 인터럽트 라인을 통해 입출력을 요청하는 인터럽트임을 인지하고, 해당 interrupt service routine으로 이동하여 입출력 작업을 수행한다.
이 과정에서 CPU가 디스크 컨트롤러에게 “파일을 읽어오라”는 명령을 한다.
- 대부분의 경우, 효율적인 자원 활용을 위해 운영체제는 입출력을 요청한 다음 CPU의 제어권을 다른 프로세스에게 이양하여 수행한다.
다른 프로세스가 CPU에서 명령을 수행하던 중 입출력 작업이 완료([디스크 —컨트롤러—> 로컬버퍼])되면, 디스크 컨트롤러가 CPU에게 인터럽트(interrupt)를 발생시켜 요청된 작업이 완료되었음을 알린다.
이때 발생한 인터럽트는 하드웨어 인터럽트이다.
CPU는 수행 중이던 사용자 프로세스를 잠시 멈추고 제어권이 운영체제로 넘어가며, interrupt service routine으로 이동하여 다음의 작업을 수행한다.
현재 수행 중인 사용자 프로그램의 정보를 PCB에 저장한다.
- [디스크 → 로컬버퍼]로 읽어온 내용을 컴퓨터 내의 메모리로 복사한다.
- 디스크 입출력을 요청했던 프로세스에게 다시 CPU를 획득할 수 있는 권한을 준다.
- 입출력을 요청했던 프로세스는 CPU를 기다리는 큐에 삽입되고, CPU의 제어권을 획득하면 하던 작업을 계속해서 수행하게 된다.
프로그램 수행 중에 CPU를 빼앗기는 경우
다음의 경우는 프로세스 수행 중 CPU를 빼앗기고 다른 프로세스가 실행되는 경우로, 문맥 교환과 관련이 있다!
- timer interrupt가 발생하는 경우
- 타이머(timer)는 특정 프로그램에 의해 CPU가 독점되는 것을 방지하기 위한 하드웨어로, CPU 할당 시간이 만료되면 인터럽트를 발생시킨다.
- 여러 프로세스가 CPU를 나누어 사용하는 시분할 시스템 구현을 위한 필수적인 요소이다.
- I/O 요청을 위해 system call을 하는 경우
- 입출력 작업은 시간이 오래 걸리므로, 해당 프로세스에게 CPU를 다시 할당하더라도 당장 다음 명령을 수행하지 못하는 경우가 일반적이기 때문에
blocked
state로 전환 후 CPU를 다른 프로세스에게 이양한다. - 입출력을 요청했던 프로세스는 입출력 요청이 완료된 후 컨트롤러가 인터럽트를 발생시키면 다시 CPU를 얻을 수 있는 자격을 부여받는다.
- 입출력 작업은 시간이 오래 걸리므로, 해당 프로세스에게 CPU를 다시 할당하더라도 당장 다음 명령을 수행하지 못하는 경우가 일반적이기 때문에
7. 프로세스의 두 가지 실행 상태
프로세스의 실행 상태 | 설명 | 호출하는 함수 |
---|---|---|
user mode running | 자신의 주소 공간에 정의된 코드를 실행하는 상태 | 사용자 정의 함수, 라이브러리 함수 |
kernel mode running | 커널의 시스템 콜 함수를 실행하는 상태 | 커널 함수 (시스템 콜) |
시스템 콜을 통해 실행되는 것이 운영체제 커널의 코드이긴 하지만, 커널이 실행 상태에 있는 것이 아니라 시스템 콜을 “호출한 프로세스”가 “kernel mode”에서 실행 상태에 있는 것이다.
사실상 프로세스가 해야 할 일을 대행하는 것이기 때문에, 시스템 콜이 실행 중일 때에도 여전히 기존 프로세스는 실행 상태에 있는 것으로 간주한다. 다만, 프로세스 자신의 코드를 실행하는 것과 구분하기 위해 “kernel mode”에서 실행 중이라고 한다.
- 시스템 콜의 실행이 끝나면 다시 user mode로 복귀하여 이후의 명령들을 계속 실행한다.
- 프로그램의 실행이 끝날 때에는 kernel mode로 진입해 프로그램을 종료한다.
References
- “운영체제와 정보기술의 원리(반효경 저)”, 4장 프로그램의 구조와 실행