고급 I/O 모델 : epoll() 함수
System Program/I/O 2014. 3. 13. 11:081. epoll() 함수
epoll() 함수는 select()와 poll() 함수와 동일하게 I/O 멀티플렉싱으로 사용된다.
단 epoll() 함수는 리눅스에서만 호환성을 갖는 한계가 있다.
epoll() 함수는 기존 두 함수에 비해서 파일 디스크립터의 준비 상태를 알리는 방식에서
더 유연성을 갖는다.
1.1. 상태 변화를 알리는 방식
- Level-Triggered Notification
- 상태 변화를 감지하고자 하는 파일 디스크립터가 준비되면 무조건 알리는 방식
- Edge-Triggered Notification
- 항상 새로 준비된 파일 디스크립터에 대해서만 알리는 방식
두 알림 방식이 마음에 잘 왔다지 않을 것이다. 쉽게 구분하는 방법은 두 번째 방식은 일단 A라는
파일 디스크립터에 대해서 알림을 받았는데 다른 새로운 파일 디스크립터가 준비되기 전에
다시 같은 A가 알림을 받을 준비가 되면 생략한다. 하지만 첫번째는 중복과 상관없이 무조건 알린다.
1.2. 각 함수별로 알림 지원 여부
I/O 모델 |
Level-Triggered |
Edge-Triggered |
select(), poll() |
O |
X |
시그널 기반 I/O |
X |
O |
epoll() |
O |
O |
시그널 기반 I/O에 대한 설명은 생략한다. 개인적으로 그 다지 좋은 방법은 아닌 것 같아서 ...
2. epoll() API 함수들
2.1. epoll_create() 함수
#include <sys/epoll.h>
int epoll_create(int size);
성공하면 파일 디스크립터를 리턴하고, 에러가 발생하면 '-1'을 리턴
매개 변수 size에는 감시할 파일 디스크립터의 수를 명시한다.
성공하면 epoll_create()는 자신의 다른 함수에서 사용할 새로운 파일 디스크립터를 리턴한다.
물론 dup() 함수 같은 것으로 다른 파일 디스크립터처럼 복사하고 이용할 수 있다.
2.2. epoll_ctl() 함수 : 관심 목록 변경 및 알림 방식 변경
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev);
성공하면 '0'을 리턴하고, 에러가 발생하면 '-1'을 리턴
[주의 사항] 디스크 파일 디스크립터는 대상에서 제외된다.
- op 매개 변수
op |
설명 |
EPOLL_CTL_ADD |
관심있는 파일디스크립터를 추가 |
EPOLL_CTL_MOD |
기존 파일 디스크립터를 수정 |
EPOLL_CTL_DEL |
기존 파일 디스크립터를 관심 목록에서 삭제 |
- epoll_event 구조체
struct epoll_event{
uint32_t events; /* epoll 이벤트 (비트 마스트) */
epoll_data_t data; /* 사용자 데이터 */
};
typedef union epoll_data {
void *ptr; /* 사용자 정의 데이터 포인터 */
int fd; /* 파일 디스크립터 */
uint32_t u32; /* 32비트 정수 */
uint64_t u64; /* 64비트 정수 */
} epoll_data_t;
2.3. epoll_wait() : 알림 기다림.
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *evlist, int maxevents, int timeout);
성공하면 준비된 파일 디스크립터 수 리턴, '0'은 타임아웃 경우, '-1'은 에러를 말한다.
준비된 파일 디스크립터를 배열로 리턴한다. maxevents는 리턴한 배열의 갯수이다.
timeout 값의 의미는 앞의 select(), poll()과 동일하므로 생략한다.
- epoll events 필드 가능한 비트 마스크
비트 |
입력 |
리턴 |
설명 |
EPOLLIN |
O |
O |
높은 순위 데이터를 제외한 데이터를 읽을 수 있다. |
EPOLLPRI |
O |
O |
높은 순위 데이터를 읽을 수 있다. |
EPOLLRDHUP |
O |
O |
상대편 소켓 shutdown 확인 |
EPOLLOUT |
O |
O |
일반 데이터를 기록할 수 있다. |
EPOLLET |
O |
X |
에지 트리거를 알림 방식으로 선택 (기본은 레벨트리거 임) |
EPOLLONESHOT |
O |
X |
이벤트를 알린 후에 이벤트 감시를 비활성화 |
EPOLLERR |
X |
O |
에러가 발생함. |
EPOLLHUP |
X |
O |
행업 발생 |
많은 면에서 poll() 함수의 이벤트와 유사하다.
3. 예제
/* * main.c -- C Test App. * * Copyright (C) 2012-2013, 2013 heesoon.kim <chipmaker.tistory.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <limits.h> #include <errno.h> #include <sys/stat.h> #include <fcntl.h> #include <time.h> #include <sys/types.h> #include <sys/epoll.h> #define MAX_BUFFER_LEN 256 #define MAX_EVENT_NUM 1 int main(int argc, char *argv[]) { int retval, m_read, m_write; int i; int fd; int epfd; struct epoll_event ev; struct epoll_event evlist[MAX_EVENT_NUM]; char buffer[MAX_BUFFER_LEN]; if((fd = open("./temp.txt", O_RDWR)) == -1) { perror("open : "); exit(EXIT_FAILURE); } /* epoll create */ epfd = epoll_create(1); if(epdf == -1) { perror("epoll_create : "); exit(EXIT_FAILURE); } /* epoll control */ ev.events = EPOLLIN; ev.data.fd = STDIN_FILENO; if(epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) == -1) { perror("epoll_ctl : "); exit(EXIT_FAILURE); } while(1) { memset(buffer, 0x00, MAX_BUFFER_LEN); retval = epoll_wait(epfd, evlist, MAX_EVENT_NUM, -1); if(retval == -1) { /* signal interrupt */ if(errno == EINTR) { continue; } else { perror("epoll_wait : "); exit(EXIT_FAILURE); } } printf("retval = %d \n", retval); for(i = 0; i < MAX_EVENT_NUM; i++) { if(evlist[i].events & EPOLLIN) { m_read = read(STDIN_FILENO, buffer, MAX_BUFFER_LEN); printf("[read] m_read = %d \n", m_read); m_write = write(fd, buffer, m_read); printf("[write] m_write = %d \n", m_write); } } usleep(1000); } close(fd); exit(EXIT_SUCCESS); }
'System Program > I/O' 카테고리의 다른 글
고급 I/O 모델 : poll() 함수 (0) | 2014.03.12 |
---|---|
고급 I/O 모델 : select() 시스템 호출 (0) | 2014.03.01 |
access() 함수 (0) | 2014.02.26 |
stat() 관련 함수 (0) | 2014.02.26 |
fcntl() 함수 (0) | 2014.02.21 |