고급 I/O 모델 : epoll() 함수

System Program/I/O 2014. 3. 13. 11:08

1. 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

 에러가 발생함.

 EPOLLHUP

 X

 행업 발생

 

많은 면에서 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
: