10-1.[os] 입출력 시스템
입출력 장치와 채널
- 필수장치 - CPU, 메모리
- 주변장치 - 입출력장치, 저장장치
저속 주변장치:
- 메모리와 주변장치 사이에 오고가는 데이터의 양이 적어 데이터 전송률이 낮은 장치
- ex) 키보드의 경우 아무리 빨리 타이핑을 한다고해도 1초에 1KB를 넘지 않음
고속 주변장치:
- 메모리와 주변장치 사이에 대용량 데이터가 오고가는 데이터 전송률이 높은 장치
- ex) 출력장치인 그래픽카드는 모니터에 초당 수십 장의 그래픽을 보여주어야함
- ex) 하드디스크도 대용량의 데이터를 메모리에 옮겨야함
주변장치는 메인보드에 있는 버스로 연결됨
채널: 데이터가 지나다니는 하나의 통로
- 도로의 차선
- 4채널 버스 = 4개의 주변장치가 동시에 데이터를 주고 받을 수 있는 4차선 도로
채널 공유, 채널 분리
주변장치는 저마다 데이터 전송 속도가 다르다
- 느린 장치 때문에 다 느려질 수도
- 전송속도가 비슷한 장치끼리 묶어서 채널 할당 -> 전체 데이터 전송속도↑
입출력 버스의 구조
초기의 구조
- 초기:
- 주변장치 몇개 없음, CPU랑 메모리 속도 느림
- 모든 장치가 하나의 버스로 연결됨
- 폴링(polling): CPU가 작업을 진행하다가 직접 입출력장치에서 데이터를 가져오는 방식
- 주변장치는 CPU랑 메모리보다 속도가 느림
- CPU가 직접 입출력하면 다른 작업을 할 수 없음
- 요리하는 시간보다 재료 옮기는 시간이 더 걸림
입출력 제어기를 사용한 구조
- CPU와 메모리의 성능이 향상됨
- 폴링 방식 안 씀
입출력 제어기
- I/O controller
- 2개의 채널 = 메인버스 + 입출력 버스
메인버스
- 고속으로 작동하는 CPU와 메모리가 사용
- 고속 주변장치(그래픽카드)가 저속 주변장치(키보드, 마우스)랑 공유하면 입출력 속도가 현저히 느려짐
입출력 버스 = 고속 입출력 버스 , 저속 입출력 버스 분리
고속 입출력 버스 - 고속 주변장치를 연결
저속 입출력 버스 - 저속 주변장치를 연결
채널 선택기(channel selector)
- 두 버스의 데이터 전송 속도를 조절
- 고속 버스는 고속 채널을 선택
- 저속 버스는 저속 채널을 선택
- 예외) 그래픽카드
- 초기: 단순 화면 출력
- 계산해야하는 양이 늘어나서 GPU를 부착
- GPU 성능이 CPU 능가
- 입출력 버스로 감당할 수 없는 대용량
- 입출력 버스에서 분리 -> 메인버스에 바로 연결하여 사용
- 포트: 주변장치를 컴퓨터에 연결하는 데 사용 (USB 꽂는 포트 생각하면 될듯)
- AGP(Accelerated Graphics Port): 그래픽 전용 포트
- 그래픽버스: 대용량 데이터를 전송하기 위해 메인버스와 직접 연결됨
- 현대의 컴퓨터: 메인버스(CPU랑 메모리 연결)+ 그래픽 버스(CPU랑 그래픽 카드 연결) + 고속 입출력 버스 + 저속 입출력 버스
- 버스 채널 = 주소 버스, 데이터 버스, 제어 버스
- 주소버스: 데이터를 가져올 주소 포함
- 데이터 버스: 실제로 송수신되는 데이터
- 제어 버스: 명령어의 시작과 종료, 데이터의 이동 방향, 오류 처리, 인터럽트 같은 다양한 신호
직접 메모리 접근
- 메모리는 보통 CPU의 명령에 따라 작동
- 직접 메모리 접근 (DMA)
- CPU 도움없이 메모리에 직접 접근할 수 있도록 입출력 제어기에 부여된 권한
- 입출력 제어기에 DMA 제어기가 붙어있음
- 채널 선택기: 여러 채널 받은 데이터 중 어떤 것을 메모리로 보낼지 결정
- 입출력 제어기: 여러 채널-주변 장치에게서 데이터를 받아 하나의 데이터 흐름을 만든다
- 채널-주변장치 -> 채널 선택기 -> 입출력 제어기 -> DMA 제어기 -> 메모리
- 메모리 -> DMA -> 체널 선택기 -> 채널-주변장치
메인 메모리:
- CPU의 작업공간
- CPU 작업공간과 DMA 작업공간이 겹침
과거:
- 별도의 '입출력 메모리'에 저장
- 단점: 입출력 메모리에서 다시 메인메모리로 데이터를 옮기는 불필요한 작업
현재:
- 메모리 맵 입출력 (memory mapped I/O):
- CPU 작업공간과 DMA 작업공간을 분리
- 공간이 겹치는 걸 막음
인터럽트
입출력과 인터럽트
- 입출력 제어기 + DMA 제어기 작업 완료 -> CPU에 인터럽트를 보냄
인터럽트: 주변장치의 입출력 요구나, 하드웨어의 이상 현상을 CPU에 알려주는 역할
- CPU가 요청한 작업을 완료했을 때
- 키보드로 데이터를 입력받았을 때
- 네트워크 카드에 새로운 데이터가 도착했을 때
- 하드웨어에 이상이 발생했을 때
IRQ
- 하드웨어의 각 장치를 구분하기 위해 붙인 번호
- 인터럽트 발생 시, 어느 장치에서 인터럽트가 발생했는지 CPU에서 파악
IRQ 번호 ≠ 인터럽트 번호
외부 인터럽트=하드웨어 인터럽트
- 주변장치 입출력 요구, 하드웨어 이상현상
- 전원 이상, 기계적인 오류
- 내부 인터럽트=예외 상황(exception) 인터럽트
- 프로세스의 오류, 예상치 못한 문제
- 숫자를 0으로 나누거나 자신의 주소 공간을 벗어나서 작업
- 시그널
- 사용자가 발생시키는 인터럽트
- ctrl+c로 프로세스 끝내기, kill 명령어
인터럽트 번호
- 내부 인터럽트는 프로세스의 잘못된 연산으로 발생하기 때문에 일단 인터럽트가 발생하면 해당 프로세스가 즉시 종료
- 코어덤프: 운영체제는 어떤 상황에서 오류가 발생했는지 파악하기 위해 프로세스가 종료되기 직전까지 메모리와 레지스터 상태를 저장
코어덤프를 확인하면 어떤 상황에서 오류가 발생했는지 알 수 있다
외부 인터럽트는하드웨어의 상태 변화로 인해 발생
- 운영체제는 어떤 하드웨어에서 인터럽트가 발생했는지 확인하기 위해 장치마다 IRQ 번호를 배정
IRQ 번호와 인터럽트 번호가 1대1로 대응됨 -
시그널은 사용자가 만들어내는 인터럽트
- 종류가 다양함
- 인터럽트 번호 128번 할당 후 세부 시그널 번호로 따로 명시
인터럽트 벡터와 인터럽트 핸들러
인터럽트 벡터
- 여러 인터럽트 중 어떤 인터럽트가 발생했는지 파악하기 위해 사용하는 자료구조
- 값이 1 -> 인터럽트 발생
- 종류와 처리방법이 다양
- 인터럽트 핸들러: 인터럽트의 처리방법을 함수 형태로 만들어놓은 것
- 인터럽트 발생 -> 인터럽트 핸들러 호출하여 작업
- 인터럽트 벡터: 인터럽트 핸들러가 저장된 메모리의 주소가 포인터 형태로 등록 -> 해당 인터럽트 핸들러를 호출
- 사용자 인터럽트인 시그널의 경우: 자신이 만든 인터럽트 핸들러 등록 가능
버퍼링
버퍼의 역할
- 속도가 다른 두 장치의 속도 차이를 완화하는 역할
- 느린 장치를 통해 들어오는 데이터를 버퍼에 모아 한꺼번에 이동 -> 효율적
- ex) 커널이 버퍼를 사용하면 입출력 작업이 완료되기 전에 다른 작업을 할 수 있어 시스템의 성능이 좋아짐
- 단일 버퍼 (single buffer)보다는 이중 버퍼(double buffer)
- 단일 버퍼: 데이터를 버퍼에 담는 작업과 버퍼에 있는 데이터를 퍼가는 작업을 동시에 못함
- 이중 버퍼: 한 버퍼는 데이터를 담는 용도, 또 한 버퍼는 데이터를 가져가는 용도
버퍼 운영 시 주의점
- 버퍼가 꽉 찼을 때: 입출력장치로 데이터를 전송하도록 설계
- 버퍼에 데이터가 꽉 차 있지 않으면: 일정 시간이 흐른 후 데이터를 전송
- 문제점: USB로 파일 옮길 때 버퍼 안의 내용은 전송 안 됨
- 하드웨어 안전 제거
- 플러시(flush): 버퍼가 다 차지 않아도 강제로 버퍼의 내용이 저장장치로 옮겨짐
- 플러시 할 때 저장장치의 손상 방지를 위해 입출력 장치 전원이 차단됨
- 프로그래밍 시 주의점:
- 파일 입출력 시:
- 작업이 끝났다 해도 버퍼에만 있고 저장장치에는 반영되지 않는 경우도 있음
- 버퍼의 내용을 강제로 저장장치로 옮김