이번에는 운영체제가 device driver를 통해서 장치를 제어하는 방식에 대해서 다뤄보겠습니다.
I/O 제어 방법
운영체제가 I/O 장치를 제어하는 방식은 크게 3가지로 나눌 수 있습니다.
Polling, Interrupt-driven I/O, DMA가 있습니다. 이 세가지에 대해서 다뤄보겠습니다.
그 전에, Interrupt가 발생하면 어떠한 수행과정을 통해서 동작이 수행되는지를 다시 한번 상기해봅시다.
1. 디바이스는 Status Register, Control Register, Data-in Register, Data-out Register로 구성되어 있습니다. 또한 device는 command-ready, busy, error의 상태를 갖습니다.
2. 가장 먼저 device driver가 device에게 명령을 요청할 때, Status Register의 busy bit를 확인합니다. 만약 busy 상태라면 busy bit가 1의 값을 갖게 될 것이고 device driver는 기다리게 됩니다. device의 상태가 ready가 아닐 때까지 말이죠.
3. device가 not busy가 되었다면, device driver는 Control Register의 write bit를 1로 만듭니다. 그 후, Data-out Register에 print할 데이터를 write합니다.
4. 그 후, device driver는 Status Register의 command-ready 비트를 1로 만듭니다.
5. device의 Controller가 command-ready bit가 1임을 확인했다면,Controller는 Status Register의 busy bit를 1로 설정합니다. 그 후, Data-out Register에 있는 데이터를 통해서 command를 수행합니다.
6. device의 동작이 완료되었다면 Controller는 Status Register의 command-ready bit와 busy bit를 0으로 만듭니다.
이러한 과정으로 Interrupt가 처리된다는 것을 인지하고 하단의 세가지 방식에 대해 어떻게 다른지 알아봅시다.
1. Polling
Polling은 device driver가 device에게 command를 수행하게 하고 난 다음 동작하는 방식으로 결정됩니다.
Polling에서 device driver는 command를 device에게 요청하고 device의 수행이 끝날 때까지 계속해서 기다립니다. device의 동작이 끝났는지를 계속 확인하면서 device의 수행이 끝났다면 user mode로 돌아가는 방식으로 진행됩니다.
마치 busy-wait의 사이클과 동일한 것입니다.
따라서 Polling 방식에서는 I/O의 동작과정이 짧다면 효울적인 방법일 것입니다. 하지만 그렇지 않고 굉장히 긴 작업으로 이루어진 동작들이 수행된다면 Polling은 하나의 프로세스가 동작이 끝나길 기다리는 시간이 낭비되므로 비효율적이라고 볼 수 있습니다.
2. Interrupt-Driven I/O
이를 보완하기 위해 Interrupt-Driven I/O 방법이 나오게 되었습니다. 해당 방법은 Device Driver가 device에게 command를 동작하게 하는 과정까지는 동일합니다. 이 후에 차별을 두어 busy waiting의 단점을 보완한 것이죠.
아래의 그림을 통해서 단계별로 설명해보겠습니다.
3번 과정 이후부터 확인해봅시다.
4. device driver는 device에게 임무를 할당한 후, process management를 통해서 run 상태인 자신의 프로세스를 block 상태로 변경을 요청합니다.
5. OS는 해당 프로세스를 block으로 변경합니다.
6. 그럼 이제 다른 process를 수행하기 위해서 process switch를 진행할 것입니다.
7. Process Scheduling에 의해서 프로세스 B가 선택되었습니다. 따라서 프로세스 B에 대한 작업들을 수행합니다.
8. 그러던 도중, 3번 과정에서 맡긴 device의 임무가 끝나게 됩니다. 그럼 그 때, device에서 IRQ(Interrupt Request)를 CPU에게 요청합니다.
9. CPU는 프로세스 B를 수행하면서 계속 Interrupt가 있는지 매 clock 마다 확인할 것입니다. 만약 해당 컴퓨터에서 프로세스가 A와 B만 있다면, IRQ Interrupt를 제외하고 다른 Interrupt가 없으므로 계속 진행하게 될 것입니다. 그러다가 IRQ가 발생하면 특정 위치에서 프로세스 B의 동작이 멈추고 Interrupt를 처리하기 위해 Kernel mode로 mode change를 진행합니다.
10. IRQ에 대한 ISR을 수행합니다.
11. ISR의 수행을 마친 후에 block되어 있던 프로세스 A를 ready로 변경시킵니다.
12. 리눅스에서는 Interrupt를 종료한 후, Return from ~ 을 수행한다고 했습니다. 여기서는 Return from Interrupt를 수행하고, 이 과정에서 signal이 변경된 process가 있는지 확인할 것입니다. 그 때, 프로세스 A의 state가 변경됨을 알게 되었고 이에 따라 Scheduler의 동작이 필요하게 되었음을 인지합니다.
13. 스케쥴러에 의해서 프로세스가 선정되고 적절한 프로세스가 user mode로 mode change되어 동작하게 됩니다.
보시는 것처럼 해당 방식은 Process Switch를 Polling에 비해 많이 필요로하게 됩니다. 만약 device의 수행 시간이 오래 걸리게 된다면 이 방식은 확실히 좋아보입니다. 하지만 수행과정이 짧다면 Process Switch를 과도하게 할 수 있으므로 Overhead의 문제도 고려해보아야할 것으로 보입니다.
3. DMA(Direct Memory Access)
우리가 I/O device에게 command를 수행하기 위해서는 메모리에서 어떠한 값을 읽어와서 수행하는 과정을 거쳐야합니다.
CPU -> Memory -> CPU -> I/O
하지만 만약 이 과정에 수없이 반복되는 일련의 동작을 I/O device에게 수행해야한다면, 이는 꽤나 쓸데 없이 CPU를 거치는 것처럼 보입니다. CPU를 거치지 않는다면 더 빠르게 진행될 수 있는 것 같기도 하죠.
그래서 메모리에게 바로 가서 I/O device에게 command를 수행할 수 있는 보조 프로세서인 DMA를 이용합니다. CPU는 단지 DMA에게 명령을 하달하고 자신의 다른 임무를 수행합니다. DMA는 요청된 명령에 의해서 메모리에서 값을 읽어와 I/O에게 요청하는 방식으로 진행되죠.
I/O device의 동작이 끝나게 된다면 DMA가 CPU에게 IRQ를 날림으로써 Polling 방식과 동일하지만 Polling의 단점을 해결할 수 있게 됩니다.
이렇게 운영체제가 I/O device를 제어하는 방법에 대해서 알아보았습니다. 감사합니다.
'CS > OS' 카테고리의 다른 글
[운영체제] RAID (1) | 2023.11.27 |
---|---|
[운영체제] 디스크 스케쥴링 (1) | 2023.11.12 |
[운영체제] 인터럽트 처리 (0) | 2023.11.11 |
[운영체제] 입출력 관리 (0) | 2023.11.11 |
[운영체제] 리눅스의 파일 시스템 (0) | 2023.11.02 |