프로그램의 구조와 인터럽트
- 프로그램의 주소 영역 = 코드 + 데이터 + 스택
- 코드 : 작성한 프로그램 함수들의 코드가 CPU에서 수행할 수 있는 기계어 명령 형태로 변환되어 저장되는 부분
- 데이터 : 전역 변수 등 프로그램이 사용하는 데이터를 저장하는 부분
- 스택 : 함수가 호출될 때 호출된 함수의 수행을 마치고 복귀할 주소 및 데이터를 임시로 저장하는 데에 사용되는 공간
- 메인함수에서 실행하다가 다른 함수를 호출하면 ⇒ 현재 위치(돌아와야 하는 지점)를 스택에 저장 ⇒ 호출 위치로 가서 명령을 수행하고 다시 스택에 저장되어 있는 복귀주소로 돌아옴
- 스택 vs 제어블록
- 일반적으로 프로그램 내에서 발생되는 함수호출에 필요한 복귀 주소는 각 프로그램의 주소 공간 중 스택 영역에 보관
- 인터럽트 때문에 CPU를 빼앗긴 위치는 운영체제가 관리하는 프로세스 제어블록(PCB)에 저장
컴퓨터 시스템의 작동 개요
- CPU는 빠른 속도로 처리하는 계산 능력은 가지고 있지만, 어떠한 작업을 수행해야 하는지 스스로 결정하는 능력은 없음
- 프로그램 카운터 (Program Counter) : CPU가 수행해야 할 메모리 주소를 담고 있는 레지스터
- CPU는 프로그램 카운터가 가리키는 위치의 명령을 처리함
- 컴퓨터 시스템의 구조
- CPU와 메모리, 각 입출력 장치를 전담하는 작은 CPU와 메모리 (device controller와 local buffer)
- 일반명령과 특권명령
- 일반명령 : 메모리에서 자료를 읽어와 CPU에서 계산하고 결과를 메모리에 쓰는 일련의 명령들, 모든 프로그램이 수행할 수 있는 명령
- 특권명령 : 보안이 필요항 명령, 입출력 장치/타이머 등 각종 장치에 접근하는 명령, 운영체제만 수행 가능
- 시스템 콜 : 사용자 프로그램에서 특권명령 수행을 위해 운영체제에게 요청하는 것
- ex. 디스크에서 작업 읽어오기 : CPU가 디스크 컨트롤러에게 데이터를 읽어오라는 명령을 내림 ⇒ 디스크 컨트롤러는 디스크로부터 데이터를 읽어와서 자신의 로컬버퍼에 저장 ⇒ 작업이 완료되면 디스크 컨트롤러가 CPU에 인터럽트를 발생시켜 완료되었음을 통지
- 주변장치들은 CPU에게 서비스를 요청하기 위해 인터럽트 라인을 세팅함, 인터럽트 종류에 따라 구분 ⇒ CPU는 매 명령 수행 직후 인터럽트 라인을 체크해서 요청이 들어왔는지 확인
프로그램의 실행
프로그램이 실행되고 있다
의 의미- 디스크에 존재하던 실행파일이 메모리에 적재된다는 의미
- 실행파일이 메모리에 적재될 때, 전체가 한꺼번에 올라가는 것이 아니라 일부만 올라가고 나머지는 디스크의 특정 영역에 내려가 있음 ⇒ 여러 프로그램이 메모리 공간을 더 효율적으로 사용하기 위해
- 프로그램이 CPU를 할당받고 명령을 수행하고 있는 상태라는 의미
- 운영체제의 커널 영역 역시 코드 + 데이터 + 스택으로 구성되어 있음
- 코드 : CPU, 메모리 등의 자원을 관리하기 위한 부분 + 사용자에게 편리한 인터페이스를 제공하기 위한 부분 + 시스템콜 및 인터럽트를 처리하기 위한 부분
- 데이터 : 각종 자원을 관리하기 위한 자료구조, CPU나 메모리와 같은 하드웨어 자원을 관리하기 위한 자료구조뿐 아니라 현재 수행 중인 프로그램을 관리하기 위한 자료구조도 저장 (프로세스 - 현재 수행중인 프로그램, PCB - 각 프로세스의 상태/CPU 메모리 사용정보 등을 유지하기 위한 자료구조)
- 스택 : 함수호출 시의 복귀 주소를 저장하기 위한 용도, 일반 사용자 프로그램과 달리 현재 수행 중인 프로세스마다 별도의 스택을 두어 관리
⇒ 커널은 일종의 공유 코드로서 모든 사용자 프로그램이 시스템 콜을 통해 접근할 수 있으므로, 일관성 유지를 위해 각 프로세스마다 커널 내에 별도의 스택을 둠
프로그램 내의 함수호출 시 해당 프로그램의 스택에 복귀주소를 저장
시스템 콜이나 인터럽트 발생으로 CPU의 수행 주체가 운영체제로 바뀌는 순간에는 직전에 수행되던 프로그램의 복귀 정보를 스택이 아닌 PCB에 저장
사용자 프로그램이 사용하는 함수
- 프로그램이 사용하는 함수는 크게 세 가지
- 사용자 정의함수
- 프로그래머 본인이 직접 작성한 함수
- 라이브러리 함수
- 직접 작성한 것은 아니지만, 누군가 작성해놓은 함수를 호출만 하여 사용하는 경우 ⇒ 1,2는 프로그램의 코드 영역에 기계어 명령 형태로 존재, 프로그램이 실행될 때 해당 프로세스의 주소 공간에 포함되며, 함수호출 시에도 주소 공간에 있는 스택사용
- 커널함수 : 시스템 콜 함수, 인터럽트 처리 함수 등
- 운영체제 커널의 코드에 정의된 함수
인터럽트
- CPU는 프로그램 카운터가 가리키는 곳에 있는 명령을 순차적으로 수행함
- 매 명령을 하나씩 수행하고 나서, 다음 명령을 수행하기 직전에 인터럽트 라인 체크 후, 인터럽트가 발생했으면 현재 하던 프로세스를 멈추고 인터럽트 처리
- Q. 인터럽트 처리 중에 또 다른 인터럽트가 발생한다면?
- 원칙적으로 인터럽트 처리 중 또 다른 인터럽트 발생하는 것을 허용하지 않음 ⇒
일관성 유지되지 않는 문제
- 하지만, 상대적으로 낮은 중요도를 가진 인터럽트를 처리하는 도중에 중요도가 더 높은 인터럽트가 발생하는 것은 허용 ⇒ 현재 처리 중이던 인터럽트 코드의 수행 지점을 저장하고 우선순위가 높은 인터럽트 먼저 처리
- 원칙적으로 인터럽트 처리 중 또 다른 인터럽트 발생하는 것을 허용하지 않음 ⇒
시스템 콜
- 시스템 콜 : 프로그램의 함수호출이기는 하지만, 자신의 주소 공간을 거스르는 영역(커널)에 존재하는 함수를 호출하는 것
- 일반적인 함수호출 : 자신의 스택에 복귀 주소 저장 후 호출된 위치로 점프
- 시스템 콜 : 주소공간 자체가 다른 곳으로 이동해야 하므로, 프로그램 자신이 인터럽트 라인에 인터럽트를 세팅하는 명령
- 인터럽트 라인이 세팅되면 CPU가 다음 명령을 수행하기 전 인터럽트 발생여부를 점검할 때 인지하고 처리함
- 프로그램이 명령 수행도중 CPU를 빼앗기는 두 가지 경우
- 타이머에 의해 인터럽트가 발생하는 경우
- 특정 프로그램이 CPU 독점하는 것을 방지하기 위함
- 입출력 요청을 위해 시스템 콜을 하는 경우
- 입출력 요청과 같이 시간이 오래 걸리는 작업이 완료되기까지 CPU를 다른 프로세스에게 이양
- 입출력 요청했던 프로세스는 요청이 완료된 후 컨트롤러가 인터럽트를 발생시킨 이후부터 다시 CPU를 얻을 수 있는 자격이 생김
프로세스의 두 가지 실행 상태
- 사용자 모드의 실행상태 (user mode running)
- 사용자 정의함수, 라이브러리 함수를 호출하는 경우
- 커널모드에서의 실행상태 (kernel mode running)
- 시스템 콜을 하는 경우
시스템 콜을 통해 실행되는 것은 프로세스의 코드가 아닌 운영체제 커널의 코드이지만, 시스템 콜이 수행되는 동안은 프로세스가 실행상태에 있다고 말함
⇒ 프로세스 입장에서는 CPU를 뺏긴 거라고 생각할 수도 있지만, 사실상 프로세스가 해야할 일을 커널이 대행하는 것이므로 시스템 콜이 실행 중일 때에도 여전히 프로세스는 실행상태에 있는 것으로 간주, 다만 구분을 위해 프로세스 A가 커널모드에서 실행중
라고 표현
프로그램의 실행이 끝날 때에는 커널모드로 진입해 프로그램을 종료함