1. 프로그램의 구조와 인터럽트
- 컴퓨터 프로그램은 어떠한 프로그래밍 언어로 작성 되었던 그 내부 구조는 함수들로 구성됨.
프로그램이 CPU에서 명령을 수행하려면 해당 명령을 담은 프로그램의 주소 영역이 메모리에 올라가 있어야 함.
주소 영역
- 코드
- 프로그램의 함수들의 코드가 CPU에서 수행할 수 있는 기계어 명령(machine instruction) 형태로 변환 되어 저장
- 데이터
- 전역 변수 등 프로그램이 사용하는 데이터를 저장
- 스택
- 함수가 호출 될 때 호출된 함수의 수행을 마치고 복귀할 주소 및 데이터를 임시로 저장하는 데에 사용되는 공간.
프로그램 실행
프로그램 따로 CPU 따로
프로그램 메인 함수 → 다른 함수 호출(CPU 메인함수의 코드를 수행하다가 다른 함수의 코드로 수행 위치 이동)
프로그램 새로운 함수 위치로 점프 → 함수 실행 → 함수 수행 완료 → 원래 호출했던 함수 위치로 돌아옴(스택에 있음)
ex)
X 함수 수행 → Y 함수 호출 → 스택에 X 함수에서 Y 함수를 호출한 지점을 스택에 저장 → Y 함수 수행 끝 → 스택에 저장된 주소 위치로 돌아와 코드를 수행
명령의 위치
함수 호출 → 다음에 실행할 명령의 메모리 위치가 바뀜
CPU가 명령을 순차적으로 수행하다가 호출된 함수의 위치로 점프해서 새로운 위치의 명령을 실행하기 때문. 호출된 함수를 모두 수행하고 나면 원래 함수가 수행되던 위치로 돌아감. 이때 스택에 저장되어 있는 복귀 주소를 사용하는 것.
인터럽트 동작 원리
프로그램 A → CPU 할당 받고 명령 수행 → 인터럽트 발생 → A 현재 수행 중인 명령의 위치 저장 → OS 인터럽트 처리 루틴 → A의 이전 작업 지점부터 수행
인터럽트는 CPU를 빼앗긴 위치는 OS가 관리하는 프로세스 제어블록에 저장됨.
프로그램
함수 호출에 필요한 복귀 주소는 각 프로그램의 주소 공간 중 스택 영역에 보관.
2. 컴퓨터 시스템의 작동 개요
CPU
→ 매 시점 메모리의 특정 주소에 존재하는 명령을 하나씩 읽어와 그대로 실행 → 수행해야 할 메모리 주소를 담고 있는 레지스터 → 프로그램 카운터(Program Counter: PC)
CPU는 매번 프로그램 카운터가 가리키는 메모리 위치의 명령을 처리
주소 이동이 없는 이상 프로그램 카운터는 항상 바로 다음 명령을 가리키게 됨.
시스템 동작
- 디스크 파일 읽기
- 키보드 입력
- 처리 결과 화면 출력
컴퓨터 시스템을 구성하는 하드웨어
- CPU, RAM
- 입출력 장치
- 입출력 장치를 전담하는 작은 CPU와 메모리(컨트롤러, 로컯버퍼)
메모리
- 메모리 위에 사용자 프로그램과 운영체제가 같이 올라가 수행됨.
- CPU는 프로그램 카운터가 가리키는 메모리 위치의 프로그램을 수행
(1)PC → 메모리 주소 중 OS 존재 → 현재 운영체제 코드를 수행, CPU는 커널 모드에서 수행
(2)PC → 메모리 주소 중 사용자 프로그램 → 사용자 프로그램 수행, 사용자모드에서 CPU 수행
일반 명령과 특권 명령
CPU가 수행하는 명령에는 일반명령과 특권명령 있음.
- 일반 명령
- 메모리에서 자료 읽기 → CPU에서 계산 → 결과를 메모리에 쓰는 것
- 일반 명령은 일반 프로그램이 수행할 수 있는 명령임.
- 특권 명령
- 보안이 필요한 명령으로 입출력 장치, 타이머 등 각종 장치에 접근하는 명령
- 운영체제만이 수행할 수 있도록 제한함.
이 두 명령의 실행 가능성 케르 위해 CPU 내에 모드비트를 두어 사용.
사용자 프로그램이 특권 명령 필요 경우
ex) 디스크 파일 접근, 수행 결과 화면 출력
사용자 프로그램 → OS에게 특권명령 대행 요청 → 시스템 콜 → 운영체제 커널 영역에 정의된 시스템 콜 처리 코드 수행
디스크에서 자료를 읽어오는 시스템 콜이라면
CPU 디스크 컨트롤러에게 데이터 읽어와 요청 → 디스크 컨트롤러 디스크에서 데이터 읽음 → 로컬버퍼에 저 → 완료 → 디스크 컨트롤러 CPU에 인터럽트 발생 → 입출력 작업 완료
주변장치 파악
CPU는 프로그램 카운터가 가리키는 메모리 위치의 명령만 계속 수행 → 주변장치 상태 파악 못 함.
주변장치 CPU 도움 필요 → 인터럽트 → CPU에게 서비스 요청
인터럽틀 발생시키기 위해 주변장치 → 인터럽트 라인 세팅 → CPU 명령 수행 후 인터럽트 라인 체크 → 인터럽트 확인 → 해당 인터럽트 처리루틴
3. 프로그램의 실행
프로그램이 실행 되고 있다. 는 것은 시스템에서 볼 때 크게 두 가지 중요한 의미를 가짐.
- 디스크에 존재하던 실행파일이 메모리에 적재된다는 의미
- CPU를 할당 받고 명령을 수행하고 있는 상태
여러 프로그램 짧은 시간 단위로 CPU 나누어 씀. 여러 프로그램이 메모리에 동시에 적재될 수 있으므로 여러 프로그램이 동시에 실행 된다는 말은 보편적임.
실행파일 메모리 적재될 때
- CPU의 수행에 필요부분 메모리에 올라감.
- 나머지는 디스크의 중 메모리의 연장 공간으로 사용되는 스왑 영역에 내려놓음.
→ 메모리 공간을 좀 더 효율적으로 사용 가능
프로세스의 주소 공간
- 코드
- 데이터
- 스택
- 각각 프로그램마다 이러한 주소 공간을 별도로 가짐.
- 프로그램 마다 독자적으로 존재하는 이와 같은 주소 공간을 우리는 가상메모리 또는 논리적 메모리라고 부른다.
→ 실제 물리적 메모리의 주소와 독립적으로 각 프로그램마다 독자적인 주소 공간을 가지기 때문에 지칭하는 용어.
운영체제
→하나의 프로그램임.
역시 코드, 데이터, 스택 주소 공간을 가지고 있다.
- 하드웨어 자원 효율적으로 관리
- 응용 프로그램 및 사용자에게 편리한 서비스 제공
→ 커널의 코드는 CPU, 메모리 등의 자원을 관리하기 위한 부분과 사용자에게 편리한 인터페이스를 제공하기 위한 부분이 주를 이룸. 이 빡에도 커널의 코드는 시스템 콜 및 인터럽트를 처리하기 위한 부분을 포함.
커널의 데이터 영역
각종 자원을 관리하기 위한 자료구조가 저장된다.
- CPU나 메모리와 같은 하드웨어 자원을 관리하기 위한 자료구조
- 현재 수행 중인 프로그램을 관리하기 위한 자료구조
현재 수행 중인 프로그램 == 프로세스(process)
커널의 데이터 영역
- 각 프로세스 상태
- CPU 사용 정보
- 메모리 사용 정보
→이 정보와 다른 정보등을 유지하기 위해 자료구조인 PCB를 두고 있다.
하드웨어, 소프트웨어 → 모든 자원을 관리하기 위한 자료구조를 각각 유지
커널의 스택
→ 일반 프로그램의 스택 영역과 마찬가지로 함수 호출시의 복귀 주소를 저장하기 위한 용도로 사용됨.
- 커널의 스택은 일반 사용자 프로그램의 스택과 달리 현재 수행 중인 프로세스 마다 별도의 스택을 두어 관리함.
프로세스가 특권 명령 수행 → 시스템 콜 → 커널에 정의된 코드
시스템 콜 내부에서 다른 함수 호출하는 경우 → 복귀 주소는 커널 내의 주소가 됨. → 사용자 프로그램의 스택과 별도의 저장공간 필요
커널 일종의 공유 코드
→ 모든 사용자 프로그램이 시스템 콜을 통해 커널의 함수 접근 가능 → 일관성 유지 하기 위해 → 각 프로세스마다 커널 내에 별도의 스택을 두게 되는 것.
정리
프로그램 → 자기 자신의 코드 내에서 함수호출 및 복귀 주소를 유지하기 위해 → 자기 주소 공간 내의 스택 사용
if 시스템 콜 or 인터럽트 발생 → 운영체제의 코드가 실행 → 코드에서 함수 호출 발생 → 커널 스택 이용
유의할 점
프로그램 내의 함수호출 시 → 해당 프로그램의 스택에 복귀 주소 저장
if 시스템 콜 or 인터럽트 발생 → CPU의 수행 주체가 OS로 바뀜 → 직전에 수행되던 프로그램 복귀 정보 → 스택 x PCB에 저장
4. 사용자 프로그램이 사용하는 함수
프로그램이 사용하는 함수
- 사용자 정의 함수
- 프로그래머 본인이 직접 작성한 함수
- 라이브러리 함수
- 프로그래머 본인이 직접 작성하지는 않았지만 이미 누군가 작성해놓은 함수를 호출만 하여 사용
→ 모두 그 프로그램의 코드 영역에 기계어 명령 형태로 존재. 프로그램이 실행 될 대 해당 프로세스의 주소 공간에 포함. 함수호출 시에도 자신의 주소 공간에 있는 스택 사용
- 커널 함수
- 운영체제 커널의 코드에 정의된 함수를 뜻함.
커널 함수 종류
- 사용자 프로그램이 운영체제의 서비스를 요청하기 위해 호출하는 시스템 콜
- 각종 하드웨어 및 소프트웨어가 CPU의 서비스를 요청하기 위해 발생시키는 인터럽트 처리 함수.
→ 커널 함수는 사용자 프로그램의 주소 공간에 그 코드가 존재하는 것이 아니라 운영체제 커널의 주소 공간에 코드가 정의됨. 즉 운영체제 내에 있는 함수를 사용자 프로그램이 호출해서 사용하는 것.
ex) 삼각함수 sin() , 화면 문자열 출력 printf() → 라이브러리이지만 궁극적으로 특권명령인 입출력을 수반 printf()내에서 커널함수를 호출하는 시스템 콜을 동반하게 됨.
운영체제 내에 시스템 콜 함수 → read() write() 함수 정의 되어있음. 입력과 출력 호출 필요로 할 때 사용됨.
일반적인 함수 호출
→ 사용자 프로그램 내에 존재하는 코드를 실행.
시스템 콜
→ 운영체제라는 별개의 프로그램에 CPU를 넘겨서 실행
CPU를 운영체제에 넘기기 위해 시스템 콜은 인터럽트와 동일한 메커니즘, CPU의 인터럽트 라인을 세팅하는 방법 사용
5. 인터럽트
CPU 특별한 일 x → 현재 수행 중인 프로세스의 다음 명령 순차적으로 수행.
CPU는 매번 프로그램 카운터가 가리키는 곳에 있는 명령 수행.
현재 수행 중인 프로세스로부터 CPU를 회수해 CPU가 다른 일을 수행하도록 하는 인터럽트 메커니즘 필요.
CPU → 매번 프로그램 카운터가 가리키고 있는 명령을 하나씩 수행 → 인터럽트 라인 세팅 확인 → 다음 명령 수행.
if 인터럽트 라인 체크 ok
인터럽트 발생 → CPU 현재 수행하던 프로세스 stop → OS의 인터럽트 처리루틴 이동 → 인터럽트 처리 수행 → 인터럽트 처리 끝 → 인터럽트 발생하기 직전의 프로세스 CPU의 제어권 다시 넘어감.
인터럽트 처리 중 또 다른 인터럽트 발생
원칙
→ 인터럽트 처리 중에 또 다른 인터럽트 발생 허용 x
이유?
→ 인터럽트 처리 중 다른 인터럽트 처리하면 데이터 일관성 유지되지 않는 문제 발생
문제
인터럽트 처리 중 → OS 커널에 정의된 데이터를 변경하는 중 → 다른 인터럽트 발생 → 앞선 인터럽트에서 변경 중이던 데이터를 또 다시 변경하게 될 수도 있음 → 두 인터럽트에 의해 데이터가 원래 의도하지 않았던 결과값으로 변경 될 가능성.
경우에 따라 예외가 존재할 필요성.
→ 인터럽트 처리 수행 중 이것보다 더 시급하거나 CPU를 당장 사용해야 하는 일이 발생.
인터럽트 마다 중요도가 다르기 때문에 상대적으로 낮은 중요도를 가진 인터럽트를 처리하는 도중에 중요도가 더 높은 인터럽트가 발생하는 것 허락할 필요가 있음.
if 중요도가 더 높은 인터럽트가 들어오면
현재 처리 중이던 인터럽트 코드의 수행 지점 저장 → 우선 순위 높은 인터럽트 처리 → 인터럽트 처리 끝 → 저장된 주소 복귀 → 이전에 수행하던 인터럽트 처리 코드 마저 수행
6. 시스템 콜
모든 프로그램 자기 자신의 독자적인 주소 공간을 지님.
프로그램 함수 호출 하는 경우 → 자신의 주소 공간 내에서 호출이 이루어지게됨.
시스템 콜
→ 함수 호출 이기는 하지만 자신의 주소 공간을 거스르는 영역에 존재하는 함수를 호출하는 것을 말함. 다시 말해 자신의 프로그램이 아닌, 커널이라는 다른 프로그램의 주소 공간에 존재하는 함수를 호출하는 것.
- 일반적인 함수호출
- 자신의 스택에 복귀 주소를 저장 → 호출된 함수 위치로 점프
- 시스템 콜
- 주소 공간 자체가 다른 곳으로 이동해야 하므로 상이한 방법 사용
방법
→ 프로그램 자신이 인터럽트 라인에 인터럽트를 세팅하는 명령을 통해 이루어짐.
프로그램이 스스로 인터럽트 라인을 세팅하는 점만 다를 뿐 일반적인 인터럽트의 발생과 동일한 방법이라 할 수 있음.
Example
디스크의 파일 입출력이 이루어지는 과정을 통해 시스템 콜 사용의 예 살펴보쟝
사용자 프로그램 → CPU에서 명령을 수행하던 중 → 디스크의 파일을 읽어와야 하는 경우 → 시스템 콜 → 커널의 함수 호출
이때 입출력 함수의 호출이 자신의 주소 공간에서 이루어질 수 없음.
사용자 프로그램 → 인터럽트 라인 세팅(OS에게 CPU를 이양하기 위해 인터럽트 라인을 세팅하는 명령을 통해 이루어짐) → CPU 인터럽트 체크 → 확인 → CPU 사용자 프로그램 잠시 멈춤 → CPU 제어권 운영체제에게 이양 → OS는 설정된 인터럽트 라인에 의해 이번에 발생한 인터럽트가 입출력을 요청하는 인터럽트임을 인지 → 서비스 루틴 이동 → 입출력 작업 수행 이 과정에서 CPU는 디스크 컨트롤러에게 파일을 읽어오라함.
디스크 컨트롤러
디스크 컨트롤러가 디스크에서 데이터를 읽어오는 일은 CPU가 명령을 수행하는 일과 비교할 때 상대적으로 많은 시간 소요됨.
입출력 진행되는 동안 CPU가 입출력의 완료만을 기다리며 명령을 수행 하지 않는 것은 비효율적임. 또한 파일 입출력을 요청한 프로세스에게 CPU의 제어권을 넘겨줄 경우, 요청한 파일 데이터 없이 다음 명령을 수행할 수 없으므로 바람직하지 않은 운영 방법
대부분의 경우 OS는 입출력을 요청 → CPU 제어권을 다른 프로세스에게 이양 → 다른 프로세스가 CPU에서 명령을 수행하던 중 입출력 작업 완료 됨 → 디스크 컨트롤러가 CPU에게 인터럽트를 발생시켜 요청된 입출력 작업 완료를 알림. → CPU는 사용자 프로세스의 수행 잠시 멈춤. → 인터럽트 처리루틴으로 그 제어권을 넘김.
이때 발생한 인터럽트는 하드웨어 인터럽트 해당하며 처리 내용은 디스크로부터 로컬버퍼로 읽어온 내용을 컴퓨터 내의 메모리에 복사한 후 디스크 입출력을 요청했던 프로세스에게 다시 CPU를 획득할 수 있는 권한을 주는 것.
해당 프로세스는 CPU를 기다리는 큐에 삽입되고 CPU의 제어권은 다시 인터럽트를 당한 프로세스로 넘어가 하던 작업 계속 수행
7. 프로세스의 두 가지 실행 상태
하나의 프로세스 수행 완료까지 프로세스
자신의 주소 공간에 있는 코드만 실행되는 것 x → 커널의 주소 공간에 있는 코드도 실행
왜?
프로그램이 사용자 정의함수, 라이브러리 함수, 커널 함수도 호출하여 실행하기 때문.
ex)
프로세스 A → CPU에서 실행
자신의 주소 공간에 정의된 코드를 실행하는 것과 커널의 시스템 콜 함수를 실행으로 볼 수 있음.
자신의 주소 공간에 정의된 코드를 실행하는 것 == 사용자모드에서의 실행 상태(user mode running)
커널의 시스템 콜 함수를 실행 == 커널모드에서의 실행 상태(kernel mode running)
주의할 점!
시스템 콜 실행 → 프로세스 A의 코드가 아닌 OS 커널의 코드
시스템 콜이 수행 되는 동안 커널이 실행 상태에 있다고 하지 않고 프로세스 A가 실행 상태에 있다고 말한다는 점!!
프로세스 A입장 → CPU를 운영체제 커널에 뺏긴 것으로 생각할 수도 있지만 커널의 코드가 실행되는 것이 사실상 프로세스 A가 해야 할 일을 대행하는 것 그래서 시스템 콜이 실행 중일 때에도 여전히 프로세스 A는 실행 상태에 있다고 간주함.
다만, 프로세스 A 자신의 코드를 실행하는 것과 구분 지어, 이러한 상태를
→ 프로세스 A가 커널 모드에서 실행 중 이라고 말함.
정리
프로그램 시작 → 종료
다양한 함수 호출 하며 실행됨. → 사용자 모드와 커널 모드의 실행 상태로 구분 지을 수 있음.
사용자 정의함수, 라이브러리 함수 호출 → 모드 변경 x 사용자 모드에서 실행 지속
시스템 콜 → 커널 모드로 진입 커널의 주소 공간에 정의된 함수를 실행. 끝나면 다시 사용자모드로 복귀해서 시스템 콜 이후의 명령들을 계속 실행. 프로그램의 실행이 끝날 때에는 커널 모드로 진입해 프로그램 종료.
'OS > OS-42study' 카테고리의 다른 글
6. CPU 스케줄링 (0) | 2023.09.13 |
---|---|
5. 프로세스 관리 (0) | 2023.09.13 |
3. 컴퓨터 시스템의 동작 원리 (1) | 2023.05.09 |
2. 운영체제의 개요 (3) | 2023.05.09 |