컴퓨터를 켜면 어떤 동작이 이루어지는 생각 해보자
컴퓨터를 켜면 자동으로 실행이 되는 프로그램이 있는데 이를 부트스트랩(bootstrap)이라고 한다.
주로 ROM이나 EPROM에 저장되며 각종 장치를 초기화시키고 운영체제를 적재하고 실행시키는 역할을 한다.
컴퓨터 시스템은 주로 위와 같이 작동한다.
CPU와 장치 컨트롤러들이 공통 버스를 통해 연결되고 소통한다. 공통 버스는 하나 이기 때문에 장치들은 CPU의 사용을 위해 서로 경쟁하는 구조이다.
각 장치들은 local buffer를 가지고 있고, I/O가 일어난다는 것은 장치로부터 컨트롤러의 버퍼에 저장되는 것을 의미한다.
이후 컨트롤러는 CPU에게 I/O가 끝났다는 사실을 알리고(Interrupt), CPU는 버퍼로부터 데이터를 읽어 메모리로 전달한다.
인터럽트가 어떻게 일어나는지 자세히 알아보자
[인터럽트]
인터럽트가 되는 방식은 2가지가 있다.
1 ) CPU가 컨트롤러의 인터럽트 요청을 감지하면, 인터럽트 번호를 읽고 이 번호를 인터럽트 벡터의 인덱스로 사용하여 인터럽트 핸들러 루틴에게 전송한다. 그런 다음 해당 인덱스와 관련된 주소에서 실행을 시작한다.
2 ) 실행되는 프로그램이 인터럽트를 발생시키는 것으로 이를 트랩이라고 한다.
cf ) 인터럽트 벡터 : 인터럽트 요청과 함께 주어진 고유의 유일한 장치 번호로 색인된 것
[인터럽트 핸들링]
인터럽트 핸들링은 인터럽트가 발생하면 모든 장치의 인덱스를 확인하여 어디에서 인터럽트가 발생했는지 확인한다. (풀링 방식)
하지만 이러한 방법은 속도가 느리고, 메모리 사용량이 많다.
이를 해결하기 위해서 인터럽트 하는 장치에서 자신의 고유 주소를 인터럽트와 함께 전송한다. 이를 벡터 방식 인터럽트라고 한다.
[I/O 구조]
I/O가 발생할 때 I/O가 발생할 때까지 CPU 작동을 멈추거나, wait loop를 하는 방식으로 I/O의 완료를 기다렸는데 이는 CPU가 작동되지 않는 시간이 많아 비효율적이다. 따라서 I/O가 처리되는 동안 CPU는 다른 사용자 프로그램이 작동되도록 한다.
이를 위해 운영체제는 모든 장치들을 관리하며, 사용자는 이를 용이하게 하기 위해 디바이스 상태 테이블을 가지고 있다. 사용자는 이런 운영체제에게 I/O를 요청함으로써(시스템 콜) I/O를 할 수 있고 CPU는 I/O를 처리하는 동안 다른 사용자 프로그램을 작동시킬 수 있다.