300x250
14. 입출력 다중화
들어가기 전에....
I/O 모델
•구분
•I/O 모드
•Blocking I/O
•Non-Blockin I/O
<!--[endif]-->
•I/O 이벤트 통지 모델
•동기
•비동기
•Blocking I/O
•유저레벨에서 커널에 I/O를 요청(그림)
•커널레벨에서 I/O를 수행
•단점
•I/O 작업이 진행되는 동안 유저레벨은 결과를 대기함
•I/O 리소스 낭비가 심함
•서버를 Blocking I/O로 구현 할 경우
•하나의 클라이언트당 쓰레드를 만듬
•쓰레드 증가에 따른 CPU의 컨텍스트 스위칭이 증가함
•비효율적임
<!--[endif]-->
•Non-Blocking I/O(select(), poll(), epoll())
•I/O를 요청하면 바로 결과를 반환
•I/O를 진행 하는 동안 유저 프로세스의 작업을 중단시키지 않음
<!--[endif]-->
•호출
•유저 프로세스가 커널에게 데이터를 받아오고 싶다고 요청
•recvBuffer에 데이터가 없으면 EWOULDBLOCK
•recvBuffer에 데이터가 있으면 버퍼로부터 데이터 복사
<!--[endif]-->
•단점
•리소스 남용
•버퍼가 준비되었는지 recv를 통해 확인해야함
•해결
•버퍼를 체크할 수 있는 방법을 구현하여 추가 함
I/O 이벤트 통지 모델
•개요
•I/O 이벤트 통지 모델의 대화주체
•커널과 프로세스
•프로세스는 커널에게 I/O 처리를 요청함
•커널은 프로세스에게 I/O 상황을 통지함
•I/O 이벤트 통지 모델은 Non-Blocking의 문제점을 해결하기 위해 고안 됨
•입력 버퍼에 데이터가 수신되어 USER로 전송 가능하거나
•출력 버퍼가 비어서 데이터의 Buffer로 전송 가능하거나
<!--[endif]-->
•구분
•커널이 프로세스에게 어떤 방식으로 통지하는가?
•동기형 통지 모델
•비동기형 통지 모델
•동기형 통지 모델
•프로세스가 커널에게 지속적으로 현재 I/O 준비 상황을 체크
•커널이 준비되었는지 계속 확인하여 동기화
•유저 프로세스가 적극적으로 확인함
•커널은 수동적으로 현재 상황을 보고함
<!--[endif]-->
•비동기형 통지 모델
•커널에게 I/O 작업을 맡김
•프로세스는 커널의 진행 사항을 인지 할 필요 없음
•유저의 프로세스가 I/O 동기화를 신경 쓸 필요가 없음
•유저 프로세스는 수동적
•커널은 적극적
<!--[endif]-->
Select()
•개요
•싱글 쓰레드로 다중 I/O를 처리하는 멀티플렉싱 통지모델의 대표적인 방법
•프로세스가 커널에게 상황 체크를 요청하는 동기형 통지 방식
•호출시 timeout에 따라 non-blocking 또는 blocking 형태가 됨
•특징
•파일 디스크립터가 I/O 준비가 되었는지를 알 수 있다면
•해당 파일 디스크립터가 할당받은 커널 Buffer에 데이터를 복사 해가면 됨
Þ파일 디스크립터의 상황을 파악할 수 있어야 함
•FD_SET 구조체를 사용하여 유저에게 파일 디스크립터의 상황을 알려줌
<!--[endif]-->
•한계
•모든 파일 디스크립터에 대해 FD_ISSET 으로 체크하는 불필요한 검사 과정
•일반적으로 검사할 수 있는 fd 개수가 최대 1024개로 제한 됨
epoll
•개요
•select의 단점을 보완하여 만든 I/O 통지 기법
•동작 구조는 select와 크게 다르지 않음
•프로세스가 커널에게 상황 체크를 요청하는 동기형 통지 방식
•호출시 timeout에 따라 non-blocking 또는 blocking 형태가 됨
•개선사항
•커널에게 정보를 요청하는 함수(select)를 호출시 발생하는 비효율 부분
•전체 관찰 대상 파일 디스크립터에 대한 정보를 넘김
•어떻게?
•관찰 대상 fd의 정보를 담은 저장소를 OS가 직접 담당
•특정 fd에 대한 정보(epoll_fd) 를 유지 할 수 있음
•전체 FD를 순회하며 FD_ISSET을 하는 문제를 해결
비교
•select
•등록된 fd를 하나하나 체크함
•커널과 user 공간 사이에 데이터 복사가 있음
•관리 fd 수에 제한이 있음
•poll
•관리 fd 무제한
•좀더 low level로 system call 호출이 select보다 적음
•epoll
•관리 fd 무제한
•select, poll과 달리 fd의 상태가 kernel에서 관리됨
•일일이 fd 세트를 kernel에 보낼 필요가 없음
•kernel이 fd를 관리하고 있기 때문에 kernel <-> User 통신 오버헤드가 대폭 줄어듬
네트워크 디바이스 드라이버의 poll()
•개요
•네트워크 디바이스 드라이버 교유의 처리 개념
•이전에 설명한 poll과 개념적으로 유사하나 동작하는 방식과 구현방법이 전혀 다름
<!--[endif]-->
•기존 처리 방식
•하드웨어에 수신된 데이터는 수신 인터럽트를 발생시킴
•하나의 수신 인터럽트는 하나의 패킷을 커널에 전달
<!--[if ppt]-->•<!--[endif]-->
•NAPI 방식(polling)
•기존 방식에서 데이터를 처리할 때 폴링 처리를 함
•하드웨어 FIFO에 수신된 데이터와 이를 처리하는동안
•새로 도착한 수신 데이터를 폴링
=> 수신된 패킷을 한번에 하나씩 처리하지 않고, 한꺼번에 처리 함
==================================================================================
(여기에서 입출력 다중화는 User Application - Kernel 간의 다중화를 의미함)
목차
1. 입출력 다중화
2. 다중 입출력의 구현
개요
•개요
•원인
•블록킹 I/O 로 인해 프로세서가 잠들수 있기에 여러 장치를 사용하는 프로그램에선 주의가 필요함
•입출력 다중화
•응용프로그램에서 select() 나 poll()을 사용함
•등록된 여러 디바이스 파일이 입출력 가능한 상태가 되거나 에러 같은 event가 발생 하면 프로세서를 깨움
1. 입출력 다중화
•배경
•하나의 프로세스로 여러 개의 디바이스를 처리할 수 있다면?
•리눅스에서는 select()와 poll(), epoll()을 지원
select() 함수
•사용
•여러 디바이스 파일에 대해 입력, 출력, 에러와 같은 사건을 등록
•하나 이상의 파일 디스크립터의 상태가 변하면 종료
•응용 프로그램은 각 이벤트를 조사해서 이벤트가 일어난 장치에 대해 처리
<!--[endif]-->
•형식
•int select(int n, fd_set *readfds, fd_set *writefds, fdset *exceptfds, struct timeval * timeout);
•readfds에열거된 파일 디스크립터들은 해당 파일 내 데이터를 read() 함수를 이용해 읽을수 있는지 검사하는 목록
•writefds에 열거된 파일 디스크립터들은 매개변수 readfds와 비슷하게 파일에 데이터를 쓸 수 있는지 검사하는 목록
•exceptfds에 열거된 파일 디스크립터들은 에러가 있는지 검사하는 목록
<!--[endif]-->
•위 세가지 중 어느 하나라도 상태가 변하거나 사건이 생기면
•select() 함수가 종료 되면서 프로세스를 깨움
•반환값으로 이 함 수에 적용시킨 FD의 상태가 실제로 어떻게 변경되었는지 가리키도록 수정 됨
•timeout에 기록된 시간이 지나면 사건이 없어도 자동적으로 프로세스를 깨우고 함수가 종료됨
<!--[endif]-->
•fd_set 집합변수를 처리하기 위한 매크로 함수
•FD_ZERO : fd_set 구조체 변수를 초기화 한다
•FD_SET : fd_set 구조체 변수에 파일 디스크립트를 등록한다
•FD_ISSET : select 함수가 종료되었을때 fd_set 구조체 변수에 해당 사건이 발생했는지 조사한다
<!--[endif]-->
poll() 함수
•개요
•select() 처럼 입출력 다중화를 처리하는 함수
•select()보다 사용하기 쉽고 좀 더 직관적임
•select() 와 마찬가지로 호출되는 즉시 프로세스를 재움
•select()와 달리 관리 file Descriptor 무제한
<!--[endif]-->
•형식
•int poll(struct pollfd * ufds, unsigned int nfds, int timeout);
•struct pollfd
{
int fd; //파일 디스크립터
short events; //요구된 이벤트
short revents; //반환된 이벤트
};
{
int fd; //파일 디스크립터
short events; //요구된 이벤트
short revents; //반환된 이벤트
};
•fd는 파일 디스크립터를 지정
•event는 프로세스가 깨어날 조건을 지정
•revents는 poll 함수가 종료 되었을때 발생된 사건이 지정됨
•events와 revents는 다음 매크로들의 조합을 이용해 깨어날 사건을 지정하거나 조사 가능
•POLLIN /POLLOUT/POLLERR/POLLHUP
•events 필드에 설정하면 읽을/쓸/에러 /hungup 상태가 되면 poll() 함수가 종료되도록 설정
•revents 필드에 설정하면 poll() 함수가 종료되었을때 읽을/쓸/에러/hungup 상태인지 검사
•POLLPRI
•주로 네트워크 패킷의 데이터 수신을 처리하기 위해 사용 됨
•디바이스 파일에서 긴급하게 데이터를 읽을 수 있는 상태가 되면 poll() 함수에서도 긴급하게 종료될 수 있게 events 필드에 설정
•poll함수가 종료되었을 때 디바이스 파일에서 긴급하게 데이터를 읽어야 할 경우 가능한 상태인지 검사하기 위해 revents 필드에 설정
2. 다중 입출력의 구현
•개요
•응용 프로그램의 입출력 다중화 함수는 select() 함수와 poll() 함수를 구현하여 해결
•이를 처리하는 디바이스 함수인 poll을 구현해야 함
•파일 오퍼레이션의 poll 함수 형태
•unsigned int xxx_poll(struct file *file, poll_table *wait);
•역할
•커널의 poll_table에 폴링 대상이 되는 사건에 대한 대기 큐를 등록
•커널에서 디바이스 파일에 입출력 다중화 처리를 구현하기 위한 마스크값을 반환
poll 함수의 구현
•디바이스 함수 xxx_poll
•형태
•정형화 되어 있음
•DECLARE_WAIT_QUEUE_HEAD(WaitQueue_Read);
DECLARE_WAIT_QUEUE_HEAD(WaitQueue_Write);
:
unsigned int xxx_poll(struct file *file, poll_table *wait)
{
int mask;
poll_wait(file, &WaitQueue_Read, wait);
poll_wait(file, &WaitQueue_Write, wait);
if(처리해야 할 입력 데이터가 있다) mask |=(POLLIN | POLLRDNORM);
if(출력이 가능하다) mask |= (POLLOUT | POLLWRNORM);
return mask;
}
DECLARE_WAIT_QUEUE_HEAD(WaitQueue_Write);
:
unsigned int xxx_poll(struct file *file, poll_table *wait)
{
int mask;
poll_wait(file, &WaitQueue_Read, wait);
poll_wait(file, &WaitQueue_Write, wait);
if(처리해야 할 입력 데이터가 있다) mask |=(POLLIN | POLLRDNORM);
if(출력이 가능하다) mask |= (POLLOUT | POLLWRNORM);
return mask;
}
•poll() 함수를 위한 대기 큐
•poll() 함수를 구현하기 위해 보통 두가지 상태의 대기 큐 변수가 필요함
•읽기용 대기 큐
•읽기 상태를 감시하기 위함
•쓰기용 대기 큐
•쓰기 상태를 감시하기 위함
•poll() 함수를 위한 대기 큐라기 보다 디바이스 드라이버의 블록킹 처리를 위한 대기 큐 임
•poll_wait() 함수
•DD의 poll() 함수는 입출력 다중화 처리를 위한 대기큐를 poll_table에 추가 해야 함
•poll_table은 커널에서 관리
•poll 함수에 전달되는 매개변수
•file 구조체 변수인 file
•디바이스 파일의 정보를 담고 있음
•poll_table 구조체의 wait 변수
•디바이스 드라이버에서 추가하는 폴링 대상이 되는 커널의 테이블 정보
•두 매개 변수를 이용해 DD의 poll() 함수에서는 poll_wait() 함수를 이용함
•poll_wait() 함수는 커널에 입출력 다중화 조건에 대한 내용을 등록
•static inline void poll_wait(struct file *filp, wait_queue_heat_t * wait_address, poll_table *p)
•poll 함수의 반환값
1.응용 프로그램에서 select나 poll 함수를 호출
2.DD에 이벤트가 있는지 조사
•poll 함수의 반환값을 조사
•0이 아닌값
•프로세스를 재우지 않고 종료
•응용 프로그램에서의 입출력 다중화 이벤트에 반영됨
•POLLIN, POLLPRI, POLLERR, POLLHUP, POLLNVAL, POLLRDNORM, POLLRDBAND, POLLWRNORM, POLLWRBAND, POLLMSG, POLLREMOVE
•읽기 가능 상태 : POLLIN | POLLRDNORM의 조합
•쓰기 가능 상태 : POLLOUT | POLLWRNORM의 조합
•에러 상태 : POLLERR 사용
3.커널은 프로세스를 재움
<!--[endif]-->
반응형
'IT > 디바이스드라이버' 카테고리의 다른 글
U-Boot와 부트로더 (3) | 2016.01.04 |
---|---|
13. 블록킹 I/O (0) | 2015.12.20 |
12. 인터럽트 처리 (0) | 2015.12.14 |
27. DMA와 PCI 디바이스 (0) | 2015.11.25 |
23. 네트워크 디바이스 드라이버 (0) | 2015.11.25 |