article thumbnail image
Published 2023. 5. 16. 03:05

PC System에는 다양한 I/O Device가 존재한다. 

예를 들어 우리는 마우스를 사용하기 위해 본체에 마우스를 연결한다. 

이렇게 연결된 마우스는 Device Controller에 의해 CPU와 상호작용 할 수 있게 된다.

Device Controller에는 Data를 Read & Write를 할 수 있는 "Data Register"를 가지고 있다.

마우스에서 클릭이 이루어지고, 우클릭을 하였는지 좌클릭을 하였는지 

CPU에게 정보를 전달해 줄 필요가 있다. 

또한, I/O Device에서 특정하게 수행해야 할 Instruction이 있다면,

CPU는 Device Controller의 Regsiter에 Instruction들을 저장한다. 

 

추가적으로 Device Controller는

I/O Device의 상태를 저장하는 "Status Register", 

I/O Device의 동작을 결정하는 "Control Register"가 존재한다.

 

 

Programmed I/O  vs.  DMA (Direct Memory Access)

CPU에서 수행되기 위해 Main Memory에 올라간다.

Main Memory에 올라간 작업 중 I/O작업이 있을 경우, 

적절한 I/O Device로 해당 Instruction을 보내줄 필요가 있다. 

 

이렇게 Main Memory와 I/O Device간의 정보 교환을 하는 방식에는 크게 2가지가 존재한다. 

  • Programmed I/O : CPU가 I/O를 담당함.
  • DMA (Direct Memory Access) : CPU가 I/O를 담당하지 않음.

 

Programmed I/O (PIO)

"Programmed I/O"란,

CPU가 직접 I/O Device와 Memory사이의 Data 교환을 직접적으로 관리하는 것을 말한다.

 

Programmed I/O에서

CPU는 Data교환 작업이 완료될 때까지 다른 작업을 수행하지 않고 기다린다

따라서, CPU자원이 낭비될 수 있다. 

 

이러한 Programmed I/O에는 2가지가 존재한다. 

  • Port I/O
  • Memory-Mapped I/O

 

Port I/O

 I/O Device는 별도의 I/O Port를 사용한다. 

즉, 다른 Port Number가 할당된다. 

 

따라서, CPU와 I/O Device간의 정보 교환을 위해서 

I/O Port에 접근하는 별도의 Instruction이 사용된다. 

Intel의 경우 In/Out Instruction을 사용한다. 

 

Memory-Mapped I/O

Device Controller의 Register들은 Physical Address Space에 매핑된다. 

따라서, 별도의 명령어가 아닌 Main Memory에서 데이터를 가져오는 

Load & Store Instruction을 통해 I/O 작업이 가능하다.

 

CPU 구현 로직은 간단해지지만, 

실제로 Physical Memory에 올라오는 것이 아닌 매핑만 되기 때문에 

Data를 가져올 때 System Bus를 타게 된다.

다른 Device간의 데이터 교환은 System Bus를 사용하게 된다.

 

Direct Memory Access (DMA)

Programmed I/O 방식에선 CPU가 I/O Device를 관리하고 데이터 전송까지 담당하였다.

그렇기 때문에, large data 이동이 필요한 경우 Programmed I/O는 효율이 떨어진다.

 

반면, "DMA"방식에선 CPU의 간섭없이 Memory와 I/O Device간의 데이터 전송이 가능하다. 

I/O작업을 맡기 위해선 Main Memory에 접근이 가능해야 한다. 

하지만, Main Memory에 접근이 가능한 것은 CPU밖에 없으므로, 

Programmed I/O에선 CPU가 이를 담당하였다. 

 

따라서, CPU의 간섭없이 I/O작업을 맡기 위해선 

특정 Device는 Main Memory에 접근이 가능해야 한다.

 

DMA방식에선 "DMA Controller"가 Main Memory에 접근할 수 있는 권한을 받으며,

System Bus와 연결되어 Main Memory와 I/O Device간의 데이터 전송을 담당한다.

CPU는 DMA Controller에 I/O Instruction의 주소만 알려주게 되면, 

DMA Controller가 알아서 처리하게 된다. 

즉, CPU는 I/O작업으로 인한 Overhead가 발생하지 않게 된다.

 

DMA의 실행과정은 다음과 같다. 

  • CPU가 DMA Controller에게 I/O Operation에 대한 정보(Address, Count ...)를 알려준다.
  • DMA Controller는 System Bus를 통해 Device Controller에게 명령을 내린다. 
  • Disk Controller는 작업이 완료되면, DMA Controller에게 알린다. 
  • DMA Controller는 Main Memory에 이를 write하고, Count(C)를 1 감소시킨다. 
  • C가 0이 될 때까지 위 과정을 반복하다가, 0이 되면 DMA Interrupt를 통해 CPU에 알린다.

 

Polling vs. Interrupt

I/O 작업이 완료되었음을 알리는 방법에는 "Polling"과 "Interrupt"방식이 있다.

 

Polling 

"Polling"은 Programmed I/O에서 I/O Device Status를 확인하기 위한 기술로,

OS가 I/O Device의 상태를 수시로 체크하는 방식이다.

 

I/O Device는 Device Controller의 Status Register를 통해 작업이 완료되었다는 것을 알린다.

OS는 주기적으로 각 Device Controller의 Status Register를 지속적으로 확인한다.

 

Interrupt

"Interrupt"란,

다른 Device에서 예외 상황이 발생하면 이를 CPU에 알리는 신호를 의미한다.

 

I/O Device는 이벤트가 발생하거나 요청한 작업이 완료되면 Interrupt를 통해 CPU에게 알린다.

즉, CPU는 I/O Device를 Check할 필요 없이 다른 작업을 수행하고, 

Interrupt가 발생하면 ISR(Interrupt Service Routine)을 실행한다.

 

하지만, 하나의 Process는 I/O작업과 CPU작업을 동시에 진행할 수 없기 때문에, 

CPU자원을 다른 Process에게 넘겨주게 된다. 

즉, Interrupt가 많이 발생한다면 Context Switching으로 인한 Overhead가 발생한다.

 

 

Blocking & Non-Blocking I/O

"Blocking I/O"는 동기적인 방식으로, 

Process는 I/O가 완료될 때까지, Suspend된다. 

 

반면, "Non-Blocking I/O"는 비동기적인 방식으로, 

I/O 작업을 요청하고 바로 return하여 다른 작업을 수행하는 방식이다.

 

Standard Inferfaces to Devices

Block Devices

"Block Device"는 데이터를 Block이라는 단위로 나누어 저장한다. 

대표적으로 Hard Disk와 SSD등이 Block Device에 속하며, 

주로 File System을 위한 저장 장치로 사용한다.

따라서, read(), write(), seek()과 같은 명령어들을 사용한다.

 

일반적으로 Sequential하게 접근하기 때문에, 

원하는 위치의 데이터를 찾기 위해 오래 걸릴 수 있다.

 

Character Devices

"Character Device"는 데이터가 Character(Byte)단위로 처리된다.

Keyboard, Mouse, Printer 등이 Character Device에 속하며, 

get(), put()등의 명령어들을 사용한다.

 

Network Devices

"Network Device"는 네트워크 연결과 관련된 Device로,

Wirteless, Ethernet, Bluetooth등이 있다. 

 

명령어로는 create(), connet(), listen(), send() 등이 있다.

 

 

Kernel I/O Subsystem

Kernel I/O Subsystem이란 I/O작업을 관리하는 Kernel의 일부로,

I/O Device와 Application간의 데이터 흐름을 관리한다.

 

Kernel I/O Subsystem은 다른 Device간의 표준화된 Interface를 제공한다.

예를 들어, read() 명령어는 표준화된 Interface를 통해

mouse로부터 read할 수 있고, Hard Disk로부터 read할수도 있다.

I/O Device들은 Device Controller를 통해 CPU와 상호작용할 수 있게 된다.

이렇게 Device Controller와 연결된 I/O Device는

System과 상호작용하기 위해 Device Driver를 통해 OS와의 연결이 필요하다.

 

"Device Driver"는 Kernel에 위치하는 SoftWare(코드)로,

이를 통해 OS는 Hadware Device와 직접적으로 소통할 수 있게 된다. 

 

이렇게 연결된 I/O Device들은 Kernel I/O Subsystem을 통해 

Application에서 I/O Device마다 별도의 Interface가 아닌 통합된 Interface로 접근이 가능해진다.

 

Kernel I/O Subsytem은 다음과 같은 기능을 제공한다. 

  • I/O Scheduling 
  • Buffering
  • Caching
  • Spooling 

 

I/O Scheduling

I/O 작업을 빠르게 처리하기 위해 I/O Reqeust 작업 순서를 정할 필요가 있다. 

저번 포스팅에서 살펴본 Disk Scheduling이 여기에 속한다.

 

Buffering

Device간의 Data 전달이 있을 때, Buffer에 저장하는 것을 말한다.

 

이는 Device간의 속도를 맞추는데 사용할 수 있다.

예를 들어, CPU에 비해 Disk는 속도가 훨씬 느리기 때문에, 

Disk로부터 Buffer에 데이터를 저장해 CPU에서 일괄적으로 처리한다.

이를 통해, CPU는 Disk에 Access시간을 줄일 수 있게 된다.

 

또한, Device간의 전송되는 Data의 Size차이를 해결하는데 사용할 수 있다.

Network Device의 경우는 패킷단위로, Disk는 Sector단위로 데이터가 전송된다.

패킷과 같이 작은 단위의 데이터를 큰 단위로, Sector와 같은 큰 단위를 작은 단위로 나누어 전송한다.

즉, Buffer에서 이들의 Size를 적절하게 만들어 서로 상호작용할 수 있게 해준다.

 

Caching

자주 쓰는 Data는 Caching을 통해 빠르게 접근할 수 있게 해준다.

 

Spooling

"Spooling"은 여러 작업들을 동시에 처리하고 대기 시간을 최소화하기 위해

중간 저장소를 통해 작업을 조율하는 방식이다.

 

Printer와 같이 Data가 번갈아 들어오는 경우 처리하지 못할 때 사용한다.

예를 들어, Printer에서 특정(A) Page를 인쇄 중에 다른 사용자가 다른(B) Page 인쇄를 요청하였다. 

그렇다면 Printer는 A를 먼저 처리하고, B를 처리해야지,

A와 B를 번갈아가면서 처리할 수 없다.

 

Spooling은 위와 같은 상황에서 가능한 장치가 있다면 B의 작업을 수행한다.

 

Summary With Example

마지막으로 Read Reqeust 예제로 정리해보자.

  • Process에서 I/O 요청을 하면 System Call을 통해 Kernel Mode로 진입하게 된다. 
  • 만약 Kernel I/O Subsystem의 Buffer 혹은 Cache에 해당 Data가 있다면 바로 돌려준다. 
  • 없다면 Device Driver에게 요청한다. (Blocking I/O라면 Process의 suspend시킨다.)
  • Device Driver는 Device Controller에게 요청한다. 
  • Device Controller에 의해 I/O Device는 이를 수행하고 완료되면 Interrupt를 날린다. 
  • Device Driver는 Data를 Buffer에 저장하고, state를 변경하여 Completion을 알린다. 
  • Kernel I/O Subsystem은 state를 통해 Completion을 알게 되고, Buffer를 통해 데이터를 Process에 맞게 만든다. 
  • 이후 System Call Return을 통해 Application에 완료되었음을 알린다.

 

 

References

Abraham Silberschatz, Peter B. Galvin, Greg Gagne의 『Operating System Concept 9th

'CS > Operating System' 카테고리의 다른 글

[OS] File System(2) - Implementation  (0) 2023.05.18
[OS] File System(1) - Interface  (0) 2023.05.17
[OS] Mass-Storage Structure  (0) 2023.05.15
[OS] Virtual Memory  (0) 2023.05.13
[OS] Main Memory(2) - Memory Allocation  (1) 2023.05.11
복사했습니다!