1. Interrupt
디바이스에 비동기적인 이벤트가 발생했을 때, 처리를 위해 운영체제(커널)에 부탁하는 것을 인터럽트라 한다. 인터럽트는 커널에 접근하여 구현된 함수를 실행하게끔 하는 Kernel entry point 중 한 가지 방식이며, 이외에도 트랩(Trap, Software Interrupt), 시스템콜(System call)이 존재한다.
비동기적이라 함은 이벤트가 발생하는 시점이 미리 정해지지 않은 경우를 말한다.
Interrupt Handling
장치들은 PIC(Programmable Interrupt Controller)를 거쳐 CPU로 신호를 전송하고, 이를 커널 스택에 저장 후 유저 모드에서 모드 체인지를 통해 커널에 진입한다.
인터럽트 처리 과정
- 유저 모드에서 인터럽트 발생 시, CPU 내부에 존재하는 레지스터 값들을 커널 스택에 저장한다. 단 이미 커널 모드에서 커널 코드를 실행 중이었다면 모드 체인지를 할 필요가 없다.
- (1) 이후 결과적으로 실행중이던 프로세스 처리를 잠시 중단하게 된다.
- Interrupt Handler 함수를 실행하여 Interrupt를 유발시킨 주체를 조사한다. PIC로부터 하드웨어의 핀 번호를 회신받는다.
- 해당 핀에 존재하는 하드웨어의 엔트리 값을 IDT(Interrupt Descriptor Table) 테이블에서 찾아 처리 함수를 실행한다. 이와 같이 특정 장치에 대해 인터럽트를 처리하는 함수를 Interrupt Service Routines라고 한다.
- 급히 처리해야 될 인터럽트들은 ISR로 분류하여 처리하고, 비교적 급하지 않은 것들을 모아 (Bottom half) 유저 모드로 되돌아가기 직전에 처리한다.
Time Slice
앞서 프로세스 스케줄링에서 학습한 타임 슬라이스를 구현할 때에도 이 Interrupt Service Routines를 이용한다. 해당되는 프로세스를 1ms마다 인터럽트가 호출되게 하고, 이를 카운트하여 100ms가 되었을 때 프로세스 스위치가 일어나게 된다.
왜 1ms 마다 인터럽트를 발생시킬까? 최대한 많이 CPU가 커널에 접근하게 하기 위함이다. 신호가 왔는지 조사한다던가, 미뤄둔 인터럽트 처리를 마저 끝내는 등의 처리가 필요한 작업들을 지연 없이 처리할 수 있게 된다. 유저 모드와 커널 모드가 동시에 병행될 수 없기 때문에, 이렇게 짧은 주기로 모드를 바꿔 주는 것이다.
Trap Handling (Software Interrupt)
Trap은 이벤트가 발생하는 시점이나 도착하는 시점이 정해져 있는 동기적(Synchronous)인 인터럽트이다. CPU가 소프트웨어의 Instruction을 실행시키면서 발행되는 인터럽트를 말한다.
예시
- 나눗셈을 하는데 분모가 0인 경우, 연산을 처리할 수 없기 때문에 인터럽트를 발생시켜 프로그램을 중단
- Segmentation fault : Instruction 안에 포함된 메모리 주소가 접근할 수 없는 주소인 경우
- Protection fault
System call
시스템콜은 커널 함수를 불러 유저 프로세스가 원하는 운영체제 서비스를 받는 것을 말한다. 시스템 콜의 종류가 무수히 많기 때문에, 기존 인터럽트가 거쳐 가는 IDT 되에도 Sys call table을 추가로 경유한다.
2. I/O Control
입출력 장치를 제어하는 3가지 방법. 해당 방법에 따라 프로그램 실행 방법이 달라지고, 컴퓨터 성능에 영향을 미친다.
Polling
프로그램은 장치를 직접적으로 제어할 수 없기 때문에, 시스템콜 방식으로 운영체제에 요청하여 장치를 제어한다. 이 시스템콜은 Kernel I/O Subsystem을 거쳐 Device Driver에 존재하는 코드를 실행시키게 명령한다. Busy bit를 통해 상태를 관리하는데, 명령을 내려 처리 중인 경우 1, 명령을 끝내면 0인 상태로 대기한다. 이렇게 비트 상태값을 체크하면서 물어보는 것을 Poll한다고 한다.
그러나 상태를 계속 확인하는 과정에서 Busy waiting이 발생하기 때문에, 처리가 오래 걸리는 입출력 장치에는 비효율적인 제어 방식이다.
Interrupt-driven I/O
인터럽트 기반 입출력 장치 제어 방식. 비트 상태값을 체크하는 과정까지는 Polling 방식과 동일하다. 이후의 Busy waiting 현상을 개선하기 위해 해당 방식이 사용된다. Device driver를 계속 반복적으로 실행하며 해당 프로세스의 처리가 끝날 때까지 기다리는 것이 아닌, 해당 프로세스를 Block 상태로 전환시키고 컨텍스트 스위치를 통해 다음 프로세스로 CPU의 자원 권한을 넘겨주는 것이다. 입출력 처리가 끝났지만 CPU 권한을 갖고 있지 않기 때문에, 인터럽트를 발생시켜 다시 해당 프로세스로 넘어오게 한다.
입출력 처리 중인 프로세스가 A, 순서를 넘겨받아 실행 중인 프로세스를 B라고 할 때 (유저모드), B의 Instruction 사이사이에 인터럽트가 발생했는지 확인하는 명령을 넣어 A의 입출력 처리가 완료 여부를 판별한다. A의 입출력 처리가 완료되어 인터럽트가 발생했을 때 B의 실행을 중단하고 커널모드로 돌아와 Interrupt Handler 커널 함수를 실행한다. Block queue에 있던 A를 깨워 Ready Queue로 이동시킨다.
처리 시간이 짧은 입출력 장치에서는 오히려 잦은 프로세스 스위치가 부하를 불러올 수 있다.
Direct Memoty Access (DMA)
컴퓨터 시스템에서 입출력이란 메인 메모리에 있는 메모리를 입출력 장치로 보내는 것인데, 직접 이동하는 것이 아닌 CPU 레지스터를 경유하게 된다. DMA에서는 CPU를 경유하는 것이 아닌, DMA 컨트롤러라고 하는 별도의 프로세서를 통해 메인 메모리의 데이터를 입출력 장치에 전달한다. CPU를 사용하지 않기 때문에, 다른 프로세스를 처리할 수 있는 여유가 생긴다는 특징이 있다.