자...
이제부터 말 하려던 본론의 서두다. Project 1에서부터 다뤄지는 인터럽트를 알아본다.
아래는 하드웨어적인 컴퓨터의 구조이다.CPU가 운영체제에게 넘어가는 경우는 interrupt, exception 두 경우가 있다.
프로세서는 보통 예외(exception)와 인터럽트(interrupt)로 구분해서 예외적인 상황을 외부로 알린다.
interrupt:
- 현 프로그램의 실행을 일시적으로 중단시키고 다른 프로그램이나 서브루틴을 시작하게 하는 외부 장치 혹은 내부의 이벤트에 의해 프로세서에 보내지는 신호.
- 외부 I/O에 의해서 발생한다. (Software에서도 Interrupt를 발생시키는데, 이것은 Trap이라고 따로 명명한다.)
- 명령어 흐름 처리와 상관없는 비동기적인(asynchronous) 사건.
자자, 넓은 의미로 Interrupt를 포괄해 말하기도 하니까 이후에 꼭 혼선 없길 바란다. 아래 두 가지이다.
쉽게 말해서~
인터럽트라는 건 CPU가 실행 중인 프로그램의 흐름을 잠시 멈추고 다른 작업을 처리하는 상황이다.
여기서 "명령어 흐름 처리와 상관없는 비동기적인(asynchronous) 사건"이라 함은 무슨 뜻일까?
예를 들어, 키보드를 눌렀다는 신호가 하드웨어 인터럽트다. 이러한 외부로부터의 인터럽트가 발생되면 프로세서는 현재 실행 중인 명령어 흐름을 잠시 멈춘다. 문자 그대로 명령어 흐름이 방해 받는다(interrupted)는 뜻이다.
이때, 프로세서는 인터럽트를 처리하는 함수 루틴으로 문맥을 전환(Context Switching)한다. 인터럽트를 처리하는 루틴을 인터럽트 서비스 루틴(interrupt service routine), 또는 인터럽트 벡터(interrupt vector)라고 한다.
인터럽트 처리가 끝나면 다시 원래 프로그램으로 돌아가 실행이 재개된다. 곧 아래에서 다룰 거지만, 멀티 태스킹의 구현도 타이머 장치가 발생하는 인터럽트로 구현된다.
CPU는 메인 메모리(RAM)에서 기계어를 읽어 한 줄 실행한 다음, 다음 기계어 실행에 앞서 매번 interrupt line에 시그널이 들어온 게 있는지 체크한다. (시그널은 I/O 장치들이 보낼 수 있다.)
CPU가 Disk에 있는 파일을 읽어오는 수행을 할 시,
CPU는 우선 Disk에 대한 device controller에게 파일을 읽어달라고 요청할 것이다. ➡️ 그런 다음 운영체제를 다른 프로세스에게 넘긴다.
➡️ device controller는 다 읽은 다음, CPU에게 "나 다 읽었어." 라고 알린다. (비동기식 입출력 (asynchronous I/O) : I/O 작업을 기다리지 않고 제어가 사용자 프로그램에 즉시 넘어간다.)
➡️ 그러면 이제 CPU는 다음 기계어의 실행에 앞서 interrupt line을 확인하고, 들어온 인터럽트를 확인하게 되겠다.
➡️ 그럼 CPU는 운영체제로 넘어가며 mode bit == 1이 되고,
CPU의 인터럽트 내용에 대한 수행이 시작된다. 이것을 기본적인 인터럽트의 개념이라고 할 수 있다.
exception:
- 폴트(fault), 중단(abort)으로 나뉘기도 한다. 구체적인 정의는 프로세서마다 약간 다를 수 있다.
- CPU가 실행할 수 없는 명령을 요청한 경우(예외 상황), CPU는 문맥을 전환(Context Switching)해 이 예외를 처리하는 핸들러를 실행하거나 혹은 현재 실행 중인 process(예외를 발생시킨 process)를 스스로 중단(죽임)시킨다.
- CPU 내부에서 발생한다. undefined 된 코드나 overflow 등이 발생의 원인이다.
- 프로그램 실행 도중 동기적(synchronous)으로 발생하는 사건.
아마 가장 대표적인 프로그램 실행 도중의 예외 현상은 페이지 폴트(page fault)일 것이다.
프로세서가 명령어 캐시에서 명령어를 읽을 때 해당 PC(Program Counter)가 가리키는 가상 주소가 아직 처리되지 않았거나 데이터를 읽는데 이 주소가 아직 페이지 테이블에 없을 때, 프로세서는 예외를 발생시키고 운영체제 즉 프로세서는 문맥을 전환(Context Switching)해 이 예외를 처리하는 핸들러를 실행시켜 이 페이지 폴트를 처리한다. 페이지 폴트가 무사히 완료되면 프로세서는 마치 페이지 폴트가 없었던 것처럼 느낄 것이다!
페이지 폴트(page fault)에 대해서 지금은 이해하지 못해도 된다! 그냥 지금은 단순무식하게 Pintos 사에서 Project 1~2 동안은 페이지 폴트 == 뻑남... 뭔가 잘못된 거임, Project 3부터는 페이지 폴트 == 페이지 폴트가 발생하는 것은 자연스러운 과정이며 얼마든지 괜찮다~ 이렇게 생각해도 된다.
그 밖에도 여러 예외가 있다. 데이터 정렬이 어긋날 때, 알 수 없는 옵 코드일 때, 메모리 접근 권한이 없을 시 예외(segment fault)가 발생한다.
예외에 대해서라면 그저 OS는 실행할 수 없는 명령을 받았을 때 예외를 발생시켜 1️⃣ 보안을 위해 프로세스를 죽이거나 2️⃣ 문맥을 전환(Context Switching)해 CPU는 운영체제로 넘어가며 mode bit == 1이 되고, 예외 처리 핸들러를 실행시켜 처리한 후, 다시 예외가 발생한 지점으로 조용히 돌아간다는 것만 알자.
그리고.... 여기서 언급되는 인터럽트 라인과 모드 비트란 뭘까?
dual-mode 개념은 Project 2에서 본격 등장하지만 어쨌든 인터럽트에 대한 이해를 위해서도 알아야 하니 간략히 살펴본다.
위의 컴퓨터 하드웨어 구조에 대한 그림을 참고하여! 읽어보자.
interrupt line:
외부 장치 또는 내부 구성 요소가 CPU(중앙 처리 장치)에 신호를 보내, 정상적인 실행을 중단하고, 특정 이벤트 또는 작업을 처리할 수 있게끔 하는 하드웨어 아키텍처 내의 전용 와이어 또는 회로.
- 하드웨어 구성 요소다.
- 인터럽트 신호가 인터럽트 라인에 수신하면, ➡️ CPU는 현재 작업을 일시 중지,
➡️ 필요한 상태 정보를 저장한 다음,
➡️ 특정 인터럽트 핸들러 루틴으로 이동하여 인터럽트 요청을 처리한다.- 인터럽트 라인은 하드웨어 설계의 필수적인 부분이며, 시간에 민감하거나 우선 순위가 높은 이벤트를 처리하기 위해 다양한 하드웨어 장치와 CPU 간의 효율적인 통신을 촉진하는 역할이다.
mode bit:
CPU를 운영체제가 실행하는 것인지, 사용자 프로그램이 실행하는 것인지 구분하게 두는 일종의 flag 또는 bit.1: 사용자 모드 -> user mode (제한된 기계어 명령만 가능)
0: 모니터 모드(OS 코드 수행) -> kernel mode (특권 명령까지 가능)
- 구현에 따라 하나의 레지스터일 수도, 회로 내의 물리적 비트가 될 수도 있다.
- 위험한 명령(특권 명령)의 경우 커널 모드에서만 수행 가능하도록 하며, 특권 명령이 감지되면 자동으로 커널 모드로 바뀌게끔 하는 일종의 보호 장치이다.