14. 입출력 다중화

Download Report

Transcript 14. 입출력 다중화

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