1. 🖥 프로그램의 구조와 인터럽트
컴퓨터 프로그램은 어떠한 프로그래밍 언어도 작성되었든 그 내부 구조는 함수들로 구성된다
프로그램이 CPU에서 명령을 수행하려면 해당 명령을 담은 프로그램의 주소 영역이 메모리에 올라가 있어야 한다
⚡️ 주소영역
코드(code) 영역
- 사용자가 작성한 프로그램 함수들의 코드가 CPU에서 수행할 수 있는 기계어 명령(machine instruction) 형태로 변환되어 저장되는 부분
데이터(data) 영역
- 전역 변수(global variable) 등 프로그램이 사용하는 데이터를 저장하는 부분
스택(stack) 영역
- 함수가 호출될 때 호출된 함수의 수행을 마치고 복귀할 주소 및 데이터를 임시로 저장하는 데에 사용되는 공간
⚡️ 함수의 호출과 인터럽트 동작원리
- 함수는 스택, 인터럽트는 프로세스 제어블록에 저장
- 둘의 작동 원리는 비슷하다
함수의 호출
- X 함수가 수행 중에 Y 함수를 호출한 경우 프로그램은 X 함수에서 Y 함수를 호출한 지점을 스택에 저장
- 함수가 수행된 후 스택에 저장된 주소 위치로 돌아와 X 함수 계속 수행
- 함수가 호출되면 다음에 실행할 명령(instruction)의 메모리 위치가 변경됨
인터럽트
- A 프로그램이 CPU를 할당 받고 명령 수행 도중 인터럽트 발생
- A는 현재 수행 중인 명령의 위치를 프로세스 제어블록에 저장
- 인터럽트 처리 루틴으로 넘어가서 인터럽트 처리
- A의 저장된 작업 지점부터 이어서 수행
2. 🖥 컴퓨터 시스템의 작동 개요
프로그램 카운터(Program Counter: PC)
CPU가 수행해야 할 메모리 주소를 담고 있는 레지스터
- 조건문, 반복문, 함수호출 등에 의한 주소 이동이 없는 이상 코드가 순차적으로 수행
컴퓨터 시스템 구성
- 컴퓨터의 시스템을 구성하는 하드웨어
- 입출력 장치와 이들을 전담하는 작은 CPU와 메모리
3. 🖥 프로그램의 실행
⚡️ 프로그램의 실행(program execution)
- 디스크에 존재하던 실행파일이 메모리에 적재
- 프로그램이 CPU를 할당받고 명령(instruction)을 수행
- 프로세스의 주소 공간은 코드, 데이터, 스택 등으로 구성
- 각 프로그램마다 이러한 주소 공간을 가짐
- 가상메모리(virtual memory) 또는 논리적 메모리(logical memory)
- 실제 물리적 메모리의 주소와 독립적으로 각 프로그램마다 독자적인 주소 공간을 가짐
- 운영체제도 프로그램이므로 운영체제 커널의 주소 공간도 코드, 데이터, 스택으로 구성
커널의 코드 영역
- CPU, 메모리 등의 자원을 관리하기 위한 부분
- 사용자에게 편리한 인터페이스를 제공하기 위한 부분
- 시스템 콜 및 인터럽트를 처리하기 위한 부분
커널의 데이터 영역
- CPU와 메모리같은 하드웨어 자원 및 수행 중인 프로그램을 관리하기 위한 자료구조 저장
- 하드웨어와 소프트웨어를 포함하는 시스템 내의 모든 자원을 관리하기 위한 자료구조 유지
프로세스(process)
프로세스란 현재 수행 중인 프로그램
- 각 프로세스의 상태, CPU 사용 정보, 메모리 사용 정보 등을 유지하기 위한 자료구조인 PCB가 있다
커널의 스택 영역
프로그램이 자기 자신의 코드 내에서 함수호출 및 복귀 주소를 유지하기 위해서는 자기 주소 공간 내의 스택 사용
시스템 콜이나 인터럽트 등으로 운영체제의 코드가 실행되는 중에 함수호출이 발생할 경우 커널 스택 사용
- 함수호출시의 복귀 주소를 저장하기 위한 용도로 사용
- 현재 수행 중인 프로세스마다 별도의 스택을 두어 관리
- 프로세스가 함수를 호출할 때 자기 주소 영역 내부에 정의된 함수를 호출하면 자신의 스택에 복귀 주소를 저장
- 프로세스가 특권명령을 수행하려고 커널에 정의된 시스템 콜을 호출하고 시스템 콜 내부에서 다른 함수를 호출하는 경우 복귀 주소는 커널 내의 주소가 되어 사용자 프로그램의 스택과는 별도의 저장공간 필요
- 커널은 일종의 공유 코드로 모든 사용자 프로그램이 시스템 콜을 통해 커널의 함수 접근 가능
- 일관성 유지를 위해 각 프로세스마다 커널 내에 별도의 스택을 둠
4. 🖥 사용자 프로그램이 사용하는 함수
- 사용자 정의함수
- 라이브러리 함수
- 커널함수
- 시스템 콜 함수, 인터럽트 처리 함수
- read(), write()
| 사용자 정의 함수 | 라이브러리 함수 | 커널함수 |
---|
정의 | 프로그래머 본인이 직접 작성한 함수 | 이미 누군가 작성해놓은 함수를 호출만 하여 사용하는 함수 | 커널의 코드에 정의된 함수 |
종류 | - | - | 시스템 콜 함수, 인터럽트 처리 함수 |
저장 공간 | 사용자 프로그램의 코드 영역 | 사용자 프로그램의 코드 영역 | 운영체제 커널의 주소 공간 |
함수호출시 사용하는 스택 | 사용자 프로그램의 주소 공간에 있는 스택 | 사용자 프로그램의 주소 공간에 있는 스택 | 커널의 스택 |
실행 과정 | 사용자 프로그램 내에 존재하는 코드 실행 | 사용자 프로그램 내에 존재하는 코드 실행 | 운영체제에 CPU를 넘겨서 실행 |
함수예시 | taeleebabo(), kido_calm_down() | sin(), printf() | read(), write() |
5. 🖥 인터럽트
- CPU는 매번 프로그램 카운터가 가리키고 있는 지점의 명령을 하나씩 수행 후 다음 명령 수행 직전에 인터럽트 라인이 세팅되었는지 확인
- 인터럽트 발생시 현재 수행중이던 프로세스 중단 후 운영체제의 인터럽트 처리루틴으로 이동해 인터럽트 처리
⚡️ 인터럽트 처리 중에 또 다른 인터럽트 발생
- 원칙적으로는 인터럽트 처리 중에 또 다른 인터럽트가 발생하는 것 허용X
- 데이터의 일관성이 유지되지 않기 때문
- 인터럽트를 처리하는 중에 운영체제 커널에 정의된 데이터를 변경하고 있는데 다른 인터럽트가 발생해 앞선 인터럽트에서 변경 중이던 데이터를 또다시 변경하게 되면 두 인터럽트에 의해 데이터가 원래 의도하지 않았던 결괏값으로 변경될 수 있기 때문
🥊 예외
현재 처리중인 인터럽트보다 더 시급하거나 CUP를 당장 사용해야하는 경우
- 인터럽트마다 중요도가 상이
- 중요도가 더 높은 인터럽트가 발생하는 것을 허락
- 이 경우 현재 처리 중인 인터럽트 코드 수행 지점을 저장 후 우선순위가 높은 인터럽트를 먼저 처리
6. 🖥 시스템 콜
자신의 주소 공간을 거스르는 영역(커널)에 존재하는 함수를 호출
- 스스로 인터럽트 라인에 인터럽트를 세팅
- 그 외엔 일반적인 인터럽트의 발생과 동일
시스템 콜 사용의 예) 디스크의 파일 입출력
- 사용자 프로그램이 CPU에서 명령 수행 중 디스크 파일을 읽어와야해 시스템 콜로 커널함수 호출
- 사용자 프로그램은 인터럽트 라인을 세팅
- CPU는 다음 명령을 수행하기 전에 인터럽트가 발생했는지 점검
- 인터럽트 인지하면 현재 수행 중인 사용자 프로그램 중단
- CPU의 제어권을 운영체제에 이양
- 운영체제는 설정된 인터럽트 라인으로 이번 인터럽트가 입출력 요청 인터럽트임을 인지
- CPU는 디스크 컨트롤러에게 파일 읽어오라고 명령
- 디스크 컨트롤러가 데이터를 읽어오는 동안 CPU는 다른 프로세스에게 제어권 이양
- 다른 프로세스가 CPU에서 명령 수행 중 입출력 작업이 완료되면 디스크 컨트롤러가 CPU에게 인터럽트 발생
- CPU는 사용자 프로세스 중단 후 인터럽트 처리루틴으로 제어권 이양 (하드웨어 인터럽트)
- 디스크로부터 로컬버퍼로 읽어온 내용을 컴퓨터 내의 메모리로 복사
- 디스크 입출력을 요청했던 프로세스에게 다시 CPU를 획득할 수 있는 권한 허락
- 해당 프로세스는 CPU를 기다리는 큐에 삽입
- CPU 제어권은 인터럽트를 당항 프로세스에게 이양해 작업 마저 수행
7. 🖥 프로세스의 두 가지 실행 상태
🚨 시스템 콜을 통해 실해되는 것이 프로세스의 코드가 아닌 운영체제 커널의 코드여도 프로세스가 실행 상태에 있다고 지칭 (커널이 실행 상태에 있다X)
🥊 프로세스가 커널모드에서 실행중