1.  입출력 시스템의 구성


1) 개요
- 입출력은 메모리와 입출력장치 사이의 자료 이전이다.
- 입출력장치는 논리 회로와 입출력장치 자체로 구성된다.
- 입출력시스템의 최상위에는 응용프로그램이 있고, 운영 체제 커널에는 장치 구동기들이 있는데, 응용 프로그램과 장치 구동기 사이의 인터페이스로서 API가 존재한다.
- 장치 구동기는 하드웨어 인터페이스를 통해서 제어기에 연결되고 제어기에 입출력 장치가 연결된다.
- 각 구성요소 사이의 인터페이스가 결정되어야 한다.

2) 제어기 ( Device Controller )
- 주변장치는 제어기에 연결된다.
- 인터페이스 3종세트; API(응용프로그램과 커널의 장치구동기 사이)
                               HW 인터페이스(장치구동기와 제어기 사이); 장치생산업체에서 제공
                               장치구동기 - 커널 인터페이스
- 제어기와 주변장치 사이의 인터페이스는 운영체제에 속하지 않고 장치를 생산하는 업체에서 제공한다.
- 제어기와 운영체제 사이의 인터페이스는 장치 구동기( Device Driver )이다.
- 입출력을 수행하기 위해서 필요한 것은 입출력을 수행하는 장치 구동기와 제어기 사이의 상호작용이다.
- 제어기에는 busy와 done의 상태와 오류를 나타내는 상태레지스터, 장치에 대한 명령을 적재할 수 있는 명령레지스터, 그리고 자료레지스터(버퍼)가 있다.

 * 응용 프로그램에서 입력요구 발생시
1. 장치구동기가 제어기의 상태레지스터를 확인한다.
2. busy/done 모두 clear 상태이면 입력 명령을 명령레지스터에 적재하고
   제어기를 가동시키고 busy 플래그를 set한다.
3. 제어기가 장치에서 버퍼로 자료 이전을 완료하면 busy 플래그를 clear, done플래그를 set한다.
4. 인터럽트를 발생시켜 CPU에게 통보한다.
5. CPU가 장치구동기를 가동하여 버퍼에서 메모리로 데이터를 읽어온다. 그리고 done 플래그를 clear로 바꾼다.


 * 응용 프로그램에서 출력요구 발생시
1. 장치구동기가 제어기의 상태레지스터를 확인한다.
2. busy/done 모두 clear이면 busy플래그를 set한다.
3. 장치구동기가 메모리에서 버퍼로 데이터를 이동시킨다.
4. 출력 명령을 명령레지스터에 적재하여 제어기를 가동시킨다.
5. 출력이 완료되면 busy플래그를 clear, done플래그를 set한다.
6. 인터럽트를 발생시켜 CPU에게 통보한다. 그리고 done플래그를 clear로 바꾼다.

- 입력과 출력은 거의 비슷하다. done플래그를 set하는것은 입력에서는 '입력을 받아서 지금 버퍼에 받아놨다.'라는 의미이고, 출력에서는 '출력을 완료했다."라는 의미이다. 입력에서는 인터럽트가 발생되고 done플래그가 set되고 난 후 CPU가 버퍼에서 메모리로 읽어오는 작업을 하지만, 출력에서는 인터럽트가 발생되고 done플래그가 set되면 그걸로 끝이다.


3) 장치구동기 ( Device Driver )
- 운영체제에서 해당되는 제어기를 통제하여 입출력을 수행하는 부분이 장치 구동기이다.
- 장치 구동기는 두가지의 인터페이스를 제공해야한다. 응용프로그래머를 위한 API와 커널과 장치구동기 사이의 인터페이스가 그것이다.
- API는 표준API를 사용하여 추상화 된 명령을 제공한다
( open/close, read/write, seek )
- 장치구동기-커널 인터페이스는 디바이스드라이버가 바뀔때마다 커널을 다시 컴파일할 수는 없으니 표준화한것.
( plug & play 기능)

 2. 인터럽트 시스템
- CPU가 제어기에게 입출력 명령을 내리고 그 응답을 기다리는 것은 CPU를 낭비하는 것이므로, 인터럽트를 사용하여 제어기가 CPU에게 작업완료를 통보하고, 그때까지 CPU는 다른 작업을 처리하는 방법을 사용한다.
- 다수준 인터럽트 : 인터럽트가 들어오면 그 인터럽트보다 낮은 수준의 인터럽트의 처리를 중지한다.
 (인터럽트마다 우선순위를 결정하는 것)
 * 인터럽트가 발생하면
1. 현재 진행중인 프로세스 또는 하위의 ISR(Interrupt Service Routine) 수행을 중단한다.
2. 프로그램 카운터 및 레지스터 값들을 보존한다.
3. 인터럽트에 해당하는 마스크를 설정한다.
4. ISR로 제어를 넘긴다. ( 프로그램 카운터를 ISR의 첫주소로 세팅 )

 * 인터럽트 처리가 끝나면 -> 보존된 레지스터의 내용을 복구한다.


 3. 장치 경영 접근방식

1) 격리형 입출력 방식과 메모리-사상형 입출력 방식
- 격리형 입출력 방식에서는 제어기의 명령레지스터에 해당하는 명령을 적재하며, CPU와 제어기의 버퍼사이에 자료를 교환한다. 따라서 주변장치를 위해서 개별적으로 레지스터를 확보해야한다. (일종의 주소 공간)
- 메모리-사상형 입출력방식에서는 메모리의 논리적 주소 공간을 그대로 사용하여 제어기의 레지스터를 메모리에 사상시킨다. 이 방식은 명령의 개수를 줄이고 사용하기에 용이해서 많이 사용되고 있다.
(즉, 이 방식에서는 제어기에 실제 레지스터가 존재하지 않고, 메모리의 일부를 할당해서 사용하는 것이다.)

2) 폴링과 인터럽트 입출력
- 폴링은 바쁜 대기 방식으로서, 입출력 명령을 내리고 난 후, 입출력이 완료될 때까지 기다린다.
 이 때, 계속해서 상태를 조사하는 방법과 일정 시간마다 상태를 조사하는 방법이 있는데 주로 후자가 쓰인다.
- 인터럽트방식은 바쁜 대기를 해소하고 입출력이 완료될때까지 CPU가 다른 작업을 할 수 있게 한다.
- 입출력 명령을 내린 프로세스는 입출력이 끝나는 것을 기다리거나 프로세스에게 그대로 제어를 넘기도록 할 수 있다. 전자를 동기 방식, 후자를 비동기 방식이라 한다.
- 동기방식의 경우 CPU는 다른 프로세스를 처리할 수 있다.

3) 직접 입출력과 DMA 입출력
- 직접 입출력은 CPU가 메모리와 제어기의 자료 레지스터 사이의 자료 이전을 직접 관장하는 것이다.
- CPU와 입출력을 동시에 사용할 수 있지만, 매 입출력을 위해 인터럽트를 처리해야하는 단점이 있다.
 이것은 문자장치의 경우에는 문제가 되지 않으나, 디스크와 같은 블록장치의 경우에는 문제가 된다.
- 이러한 문제를 해결하기 위해 CPU의 도움 없이 독자적으로 메모리에 접근하여 한 입출력 명령으로 많은 자료(블록)를 입출력 및 전송하고, 한 블록의 처리가 끝날때마다 한번의 인터럽트를 발생시키는 방법을 쓴다.
 이 방식이 직접 메모리 접근(DMA) 방식이다.
- 즉, DMA입출력에서는 매 바이트마다 인터럽트가 발생하지 않고 한 블록에 한 인터럽트가 발생한다.

- 디스크에서 사용하는 시스템 버퍼는 블록 단위로 시스템 버퍼 풀에서 배정된다.
- 디스크 입출력 요구가 많아질 경우 작업의 큐로 형성되고 인터럽트 처리기에 의해 스케쥴되어 실행된다.
 디스크의 seek time 최적화를 위한 것이다.

- cycle stealing : CPU와 DMA가 동시에 메모리 접근을 요구하게 되면 DMA에게 우선권을 주고 CPU는 한 사이클을 쉰다.


 4. Buffering과 Spooling

1) 버퍼링 (Buffering)
- 서로 속도가 다른 하드웨어 사이에 자료 레지스터를 추가하여 속도를 개선하는 방법을 버퍼링이라 한다.
- 프로세스가 제어기의 자료레지스터A에 있는 자료를 읽는 동안, 제어기는 자료레지스터B에 다음 자료를 적재하는 것 같은 방법을 이중 버퍼링이라 한다.

2) 스풀링 (Spooling)
- 출력 명령이 주어지면 먼저 그 데이터를 디스크의 일정 장소에 저장하고, 별도의 출력 프로그램이 저장된 데이터를 순차적으로 프린터에 내보내는 방식을 스풀링이라 한다.
- 출력을 전담하는 프로그램을 스풀러라고 한다. 스풀러는 스풀 영역의 큐 정보를 감시하다가 생성되면 파일을 출력하는 기능을 한다.


 5. 입출력 프로세스의 처리

1) 비동기 VS 동기 입출력
- 비동기/동기 입출력은 응용 프로그램쪽에서 장치를 사용하는 관점에서의 차이가 있다.
- 동기식은 입출력을 시작시키고 그 작업이 끝날때까지 프로세스가 대기한다. CPU가 다른 프로세스에 사용된다.
- 비동기식은 입출력을 시작시키고 바로 다음 연산을 수행한다. 입출력과 상관없이 그 프로세스가 계속 CPU를 사용할 수 있다.
 입출력 종료를 알려주는 방법이 필요하다. ex)이벤트.
- 따라서 비동기식에서는 Call-back function을 구현해야 하며, Kernel thread를 사용할 수 있어야 한다.

2) 입출력장치 큐
- 입출력 장치는 빈번하고, 입출력장치의 속도는 느리기 때문에 입출력 프로세스들은 큐를 사용해서 작업을 대기시킨다.
- 키보드나 마우스처럼 언제 입력이 들어올지 모르는 장치들은 요구가 없는 상태에서도 인터럽트 처리기를 통해 버퍼링해 놓는다.

 6. 하드웨어에 의한 보호

- 운영 체제가 하는 일이 많아지고 입출력과 관계하여 할 일이 많아지게 되자, 시스템의 효율성을 높이기 위해서 시스템내의 많은 자원을 여러 프로그램이 동시에 공유하도록 하였다. 한 프로그램이 CPU를 사용하는 동안 다른 프로그램들이 입출력을 수행할 수 있게 되었고(다중 프로그래밍과 인터럽트), 여러 프로그램이 동시에 메모리를 사용할 수도 있게 되었다.
- 이런 자원의 공유는 시스템의 활용도를 높이는 반면에, 사용하는 자원을 보호해야하는 문제가 생겼다.
- 운영체제가 처리할 수 있는 오류(계산상의 오버플로우 등) 같은 경우는 기계가 멈추지 않지만, 프로그램이 운영체제의 영역을 침범하여 손상시키거나 입출력 프로그램에서 인터럽트를 잘못다루는 경우가 생기면 기계가 멈출 수 있다.


1) 이중 모드
- CPU의 상태레지스터 중 1비트를 모드 비트로 사용한다. 0이면 커널모드이고 1이면 사용자모드이다.
- 사용자 프로세스의 코드영역에 있는 명령어를 실행하는 경우, 사용자 모드로 실행한다. 인터럽트나 시스템/입출력 제어와 관련된 특권 명령을 수행할 수 없다. 메모리 참조 영역도 메모리 보호 하드웨어에 의해서 제한된다.
- 운영체제 코드영역에 있는 명령어를 실행하는 경우, 커널 모드로 실행한다. 하드웨어적인 제한이나 보호를 수행하지 않는다.
 사용자 프로그램에서 시스템 호출(트랩), 인터럽트 처리, 감지된 사용자 오류(트랩) 발생 시에 커널 모드가 된다.
- 사용자모드에서 커널모드로의 전환은 프로그램에서 독자적으로 할 수 없다.

2) 입출력 보호
- 불법 IO명령을 막기 위해 모든 IO명령을 특권 명령으로 구성하는 방법이 있다.
- 프로세스가 IO명령을 하기 위해서는 커널 모드로의 전환(특권 획득)이 필요한 것이다.

3) 메모리 보호
- 일반적으로 사용자는 사용자 모드에서 운영체제 영역 안의 인터럽트 테이블 및 처리기를 포함한 모든 영역에 접근하거나 수정할 수 없다. 또한 사른 사용자의 영역에도 마찬가지이며 자신의 코드 영역에 쓰는 것도 불가능하다.
- Base와 Limit레지스터를 사용하여 프로그램 공간을 정의해 놓음으로서 보호한다.
- 사용자 모드에서 주소를 생성했을 때에 확인하여 만약 범위(Base~Limit)를 벗어난 주소가 나오면 커널로 트랩한다.
- 리눅스나 유닉스커널에서는 segmentation fault가 발생한다.

4) CPU 보호
- 사용자 프로그램이 무한 루프에 들어가서 운영체제에게 제어를 넘기지 않으면 문제가 되므로, 제어권을 가져올 방법이 필요하다.
- 타이머 또는 클럭이라고 부르는 장치로 정해진 시간마다 인터럽트를 발생시킨다. 이 인터럽트는 정전이나 하드웨어 결함을 제외하고 가장 높은 우선순위의 인터럽트이다.
- 타이머가 있기 때문에 프로그램의 실행 시간이 제한되고 무한루프로 인한 CPU 독점을 방지할 수 있다.


 7. 기억장치 구조

- 하드웨어는 CPU, 메모리 그리고 주변장치로 구성된다.

- 메모리와 프로세서 안에 있는 레지스터들은 CPU가 접근할 수 있는 유일한 장치들이다.
- 메모리 접근 속도가 레지스터에 비해 상대적으로 느리기 때문에, CPU의 속도를 좌우하는 것은 메모리의 속도이다.
- CPU의 연산속도와 메모리 접근시간의 격차를 줄이기 위한 하드웨어적 기법으로 캐시 메모리를 사용한다.

- 디스크의 접근시간은 seek time, rotational delay, 입출력시간 및 전송시간으로 이루어진다.
- 디스크의 seek time은 CPU에 비해 매우 느리기 때문에 시스템의 성능을 저하시킨다.
- 디스크의 seek time을 줄이기 위해 버퍼링 기법이나 디스크 스케줄링을 사용한다.


 8. 기억장치 계층

- 다양한 기억장치는 속도와 가격에 따라서 계층 구조를 갖도록 조직할 수 있다.
- 계층구조는 속도, 용량, 가격의 비교 뿐만이 아니라, 하드웨어나 운영체제에 의한 버퍼링의 개념이 추가되어야 완성된다고 할 수 있다.
- 계층구조의 궁극적인 목적은 용량은 최하위 기억장치의 크기처럼, 접근 속도는 최상위 기억장치의 속도처럼 사용하는데에 있다.

1) 캐시
- 두 기억장치 사이에 접근시간이나 이동속도의 격차가 있을 때, 이를 완화하기 위해서 사용한다.
- CPU에서 메모리에 접근하는 경우 그 자료를 메모리보다 속도가 빠른 캐시에 복사하는 용도로도 사용한다.
- 알고리즘에 따라서는 90%이상의 확률로 캐시가 필요한 데이터를 가지고 있을 수 있다.




'학부 전공 > 운영체제' 카테고리의 다른 글

6. 병행 프로세스  (0) 2011.06.17
1. 운영체제 소개  (0) 2011.03.09

+ Recent posts