이전 글에서 System call이 발생하면 interrupt를 통해서 user mode에서 kernel mode로 변경시킨다는 내용을 언급한 적이 있었습니다. 이번 글에서는 이 interrupt의 발생에 대해 조금 더 자세히 알아보고자 합니다.
1. Interrupt란?
우선 interrupt라는 게 무엇인가에 대해 먼저 알아야 합니다. Interrupt란 CPU가 어떤 작업을 실행하고 있을 때 어떠한 이유 때문에 우선적으로 처리가 필요한 작업이 생겨 이를 CPU에 알리는 행위를 말합니다. Interrupt가 발생하면 바로 CPU는 하던 작업을 멈추고 interrupt handler라는 것을 실행하게 됩니다.
2. Interrupt의 발생 원인은?
Interrupt를 발생시키는 요인은 두가지로 분류할 수 있습니다.
1. H/W interrupts
하드웨어에 의해 일어나는 interrupt들은 우리에게 친숙한 부분들이 많습니다. 대표적인 예시로는 키보드나 마우스로 어떤 이벤트를 발생시키는 것이 있습니다. CPU는 어떤 작업을 수행하고 있다가도 우리가 마우스로 어떤 버튼을 클릭하게 되면 하던 작업을 멈추고 마우스가 클릭한 버튼에 해당하는 작업을 수행하게 됩니다. 이 외에도 타이머에 의한 interrupt, DMA에 의한 interrupt 등이 있습니다. DMA에 관해서는 다른 글에서 자세하게 설명할 기회가 있을 것으로 생각됩니다. 이렇게 하드웨어에 의해 interrupt가 발생하면 이는 system bus를 통해 CPU에 전달이 됩니다.
2. S/W interrupts
소프트웨어에 의해 발생하는 interrupt가 바로 System call입니다.
3. Interrupt의 처리
발생한 interrupt를 처리하는 일은 CPU의 주요한 기능 중 하나입니다. 모든 interrupt는 그 interrupt에 해당하는 interrupt handler를 개별적으로 가지고 있습니다. Enter 키를 눌렀을 때와 Space bar를 눌렀을 때 서로가 다른 기능을 해야 하는 것을 떠올려보면 이해가 쉬울 것 같습니다. Enter를 눌렀을 때는 Enter를 위한 interrupt handler가, space bar를 눌렀을 때는 space bar를 위한 interrupt handler가 실행되어야 하는 것이죠.
CPU는 interrupt의 발생을 감지하자마자 해당 interrupt에 대한 interrupt handler를 실행시킵니다. (Interrupt handler는 interrupt service routine이라고도 불립니다.) 물론 이 interrupt에 대한 처리는 굉장히 빠르게 수행되어야 하며, 기존에 CPU에서 수행하고 있던 작업 역시 어딘가에 저장을 해 두어야 합니다. 구체적으로는 실행중이던 instruction의 주소와 그 register의 상태 등을 저장해두어야 할 것입니다. 이를 CPU context라고 하죠. 그리고 interrupt handler를 수행한 뒤에 다시 context를 가져와서 원래 하던 작업을 이어서 수행하게 됩니다.
그렇다면 interrupt handler는 어디에 저장되어 있는가? 모든 interrupt들은 저마다의 숫자가 부여되어 있습니다. 그리고 모든 운영체제들은 부팅될 때 메모리에 Interrupt Descriptor Table, 줄여서 IDT라는 것을 생성합니다. 이 IDT의 주소는 CPU의 한 register에 저장되어있죠. 그리고 이 IDT에는 각 interrupt들에 대한 handler들의 주솟값을 저장되어 있습니다. Interrupt가 발생하면 CPU는 발생한 interrupt의 번호와 IDT의 주소를 이용해서 메모리의 어디에 해당 interrupt의 handler가 구현되어 있는지를 찾습니다. 그리고 발견한 handler를 이용하여 interrupt를 처리하게 됩니다. 아래의 그림을 보면 이해가 조금 더 쉬울 것 같습니다.
4. System call이 발생하면?
앞에서 말했듯이 System call은 소프트웨어에 의해 발생되는 interrupt의 한 종류입니다. System call에도 당연히 여러 종류가 있겠죠? memory에 접근하는 System call도 있을 것이고, 입출력과 관련된 System call도 있을 것입니다. 마치 위에서 말한 Enter key와 space bar처럼요. 이 각각의 System call에도 숫자가 메겨져 있습니다. 그리고 이 숫자와 각 System call에 의해 수행되어야 하는 함수들이 매핑되어 System Call Table이라는 곳에 정리되어 있죠.
System call이 발생하면 위에서 살펴본 interrupt의 처리과정과 동일하게 IDT에서 handler의 위치를 찾습니다. System call이 실행될 때는 Kernel mode에서 실행해야 하기 때문에, 이 때 이미 CPU mode는 User mode에서 Kernel Mode로 바뀌게 됩니다. 그리고 handler를 실행하게 되죠. 그럼 그 interrupt handler 내부에서 System call table에 저장된 해당 System call이 구현된 주소를 찾아서 호출하게 됩니다. 이 호출된 함수가 실제로 호출된 기능을 수행하게 됩니다. 이것도 그림으로 보면 더 이해가 빠를 것 같습니다.
예를 들어 write()함수를 실행시켜야 한다고 가정해보겠습니다. 처음에 코드에서 write() 함수를 실행함으로써 System call이 발생하면, 이 wirte의 handler를 IDT에서 찾아서 실행하게 됩니다. Handler는 write() 함수의 System call number를 참고하여 System Call Table에서 실제로 write() 함수가 어디에 구현되어 있는지 확인하고 그곳으로 이동해 실제로 그 기능이 구현되어 있는 sys_write()라는 함수를 실행시키게 됩니다.
오늘은 Interrupt의 발생과 처리에 대해 정리를 해보았습니다. 이렇게 번거로운 과정을 거치는 이유는 이번에도 당연히 보안(Protection)때문입니다. 그리고 각 응용 프로그램들이 잘 정의되어 있는 "Public Function"들을 호출할 수 있도록 하는 것도 한 가지 이유입니다. 하지만 interrupt를 활용하는 것은 굉장히 복잡한 과정을 거치기 때문에 API라는 것을 통해 System call을 호출하기도 합니다. 이 부분은 나중에 공부하게 된다면 다시 업로드 하도록 하겠습니다. 읽어주셔서 감사합니다.
'전공공부 > 운영체제 (Operating System)' 카테고리의 다른 글
[운영체제] Thread (1) - Definition, Implementation, and Multicore (1) | 2020.12.18 |
---|---|
[운영체제] Processes (3) - Interprocess Communication (IPC) (0) | 2020.12.17 |
[운영체제] Processes (2) - Process Creation & Termination (0) | 2020.12.17 |
[운영체제] Processes (1) - Process State, PCB (1) | 2020.12.17 |
[운영체제] Introduction & Operating System Structure (2) | 2020.12.16 |