NAME

epoll_ctl - epoll 파일 디스크립터 제어 인터페이스

SYNOPSIS

#include <sys/epoll.h>

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

DESCRIPTION

이 시스템 호출을 사용해 파일 디스크립터 epfd가 가리키는 epoll(7) 인스턴스의 관심 목록에서 항목을 추가, 변경, 제거한다. 대상 파일 디스크립터 fd에 대해 동작 op를 수행하기를 요청한다.

op 인자에 유효한 값은 다음과 같다.

EPOLL_CTL_ADD
epoll 파일 디스크립터 epfd의 관심 목록에 항목을 추가한다. 항목은 열린 파일 기술 항목(epoll(7)open(2) 참고)에 대한 참조인 파일 디스크립터 fd, 그리고 event에 지정한 설정으로 이뤄진다.
EPOLL_CTL_MOD
관심 목록에서 fd에 연계된 설정을 event의 새 설정으로 바꾼다.
EPOLL_CTL_DEL
관심 목록에서 대상 파일 디스크립터 fd를 제거(등록 해제)한다. event는 무시되며 NULL일 수 있다. (하지만 아래 BUGS 참고.)

event 인자는 파일 디스크립터 fd에 연결할 객체를 기술한다. struct epoll_event가 다음처럼 정의돼 있다.

typedef union epoll_data {
    void        *ptr;
    int          fd;
    uint32_t     u32;
    uint64_t     u64;
} epoll_data_t;

struct epoll_event {
    uint32_t     events;      /* epoll 이벤트 */
    epoll_data_t data;        /* 사용자 데이터 변수 */
};

epoll_event 구조체의 data 멤버는 커널에서 저장하고 있다가 이 파일 디스크립터가 준비 상태가 되었을 때 (epoll_wait(2)을 통해) 반환되는 데이터를 나타낸다.

epoll_event 구조체의 events 멤버는 다음 이벤트 종류들을 0개 이상 OR 해서 구성한 비트 마스크다.

EPOLLIN
연계 파일을 read(2) 동작에 사용할 수 있다.
EPOLLOUT
연계 파일을 write(2) 동작에 사용할 수 있다.
EPOLLRDHUP (리눅스 2.6.17부터)
스트림 소켓의 상대가 연결을 닫았거나 연결의 쓰기 쪽을 닫았다. (이 플래그는 특히 에지 트리거 사용 시 간단한 코드 작성으로 상대의 shutdown을 탐지하는 데 유용하다.)
EPOLLPRI
파일 디스크립터에 어떤 예외 상황이 있다. poll(2)POLLPRI 설명 참고.
EPOLLERR

연계 파일 디스크립터에서 오류 상황이 발생했다. 또 파이프의 읽기 쪽이 닫혔을 때 쓰기 쪽에서 이 이벤트가 보고된다.

epoll_wait(2)이 항상 이 이벤트를 보고하므로 epoll_ctl() 호출 시 events에 설정하지 않아도 된다.

EPOLLHUP

연계 파일 디스크립터에서 연결이 끊겼다.

epoll_wait(2)이 항상 이 이벤트를 보고하므로 epoll_ctl() 호출 시 events에 설정하지 않아도 된다.

참고로 파이프나 스트림 소켓 같은 채널에서 읽기를 할 때 이 이벤트는 상대가 채널의 그쪽 끝을 닫았다는 표시일 뿐이다. 그 채널의 미처리 데이터를 모두 소비한 후에야 채널 읽기가 0(파일 끝)을 반환하게 된다.

EPOLLET

연계 파일 디스크립터에 에지 트리거 알림을 요청한다. epoll의 기본 동작 방식은 레벨 트리거다. 에지 트리거 및 레벨 트리거 알림에 대한 자세한 정보는 epoll(7)을 보라.

이 플래그는 epoll_ctl() 호출 시 event.events 필드에 입력하는 플래그다. 절대 epoll_wait(2)에서 반환되지 않는다.

EPOLLONESHOT (리눅스 2.6.2부터)

연계 파일 디스크립터에 단발 알림을 요청한다. 즉 epoll_wait(2)으로 파일 디스크립터에 대한 이벤트 알림을 받고 나면 관심 목록에서 연계 파일 디스크립터가 비활성화되어 epoll 인터페이스가 다른 이벤트를 보고하지 않게 된다. 그 파일 디스크립터를 재활성화하려면 사용자가 새 이벤트 마스크로 epoll_ctl() EPOLL_CTL_MOD를 호출해야 한다.

이 플래그는 epoll_ctl() 호출 시 event.events 필드에 입력하는 플래그다. 절대 epoll_wait(2)에서 반환되지 않는다.

EPOLLWAKEUP (리눅스 3.5부터)

EPOLLONESHOTEPOLLET가 설정돼 있지 않고 프로세스에게 CAP_BLOCK_SUSPEND 역능이 있으면 이 이벤트가 대기 중이거나 처리 중인 동안 시스템이 "대기"나 "하이버네이션"으로 들어가지 않게 한다. epoll_wait(2) 호출이 이벤트를 반환한 시점부터 시작해서 같은 epoll(7) 파일 디스크립터에 다시 epoll_wait(2)를 호출하거나, 그 파일 디스크립터를 닫거나, EPOLL_CTL_DEL로 이벤트 파일 디스크립터를 제거하거나, EPOLL_CTL_MOD로 이벤트 파일 디스크립터에서 EPOLLWAKEUP를 없애기까지를 "처리 중"이라고 본다. BUGS도 참고.

이 플래그는 epoll_ctl() 호출 시 event.events 필드에 입력하는 플래그다. 절대 epoll_wait(2)에서 반환되지 않는다.

EPOLLEXCLUSIVE (리눅스 4.5부터)

대상 파일 디스크립터 fd에 붙는 epoll 파일 디스크립터에 배타적 깨우기 모드를 설정한다. 깨우는 이벤트가 발생했는데 같은 대상 파일에 여러 개의 epoll 파일 디스크립터가 EPOLLEXCLUSIVE로 붙어 있으면 그 epoll 파일 디스크립터들 중 한 개 또는 그 이상이 epoll_wait(2)으로 이벤트를 수신하게 된다. 그런 경우에 (EPOLLEXCLUSIVE가 설정돼 있지 않을 때의) 기본 동작은 모든 epoll 파일 디스크립터들이 이벤트를 수신하는 것이다. 따라서 특정 상황에서 단체로 깨어나기(thundering herd) 문제를 피하는 데 EPOLLEXCLUSIVE가 쓸모가 있다.

여러 epoll 인스턴스에 같은 파일 디스크립터가 있는데 일부에는 EPOLLEXCLUSIVE 플래그를 썼고 나머지는 그러지 않았다면 EPOLLEXCLUSIVE를 지정하지 않은 epoll 인스턴스들에는 모두 이벤트가 제공되고 EPOLLEXCLUSIVE를 지정한 epoll 인스턴스들은 그 중 최소 하나에 이벤트가 제공된다.

EPOLLEXCLUSIVE와 함께 지정할 수 있는 값들은 EPOLLIN, EPOLLOUT, EPOLLWAKEUP, EPOLLET이다. EPOLLHUPEPOLLERR도 지정할 수는 있지만 그럴 필요가 없다. 언제나처럼 그 이벤트들은 events에 지정했는지 여부와 상관없이 발생하면 항상 보고된다. events에 그 외의 값을 지정하려고 하면 EINVAL 오류가 난다.

EPOLLEXCLUSIVEEPOLL_CTL_ADD 동작에만 쓸 수 있다. EPOLL_CTL_MOD에 쓰려고 하면 오류가 난다. epoll_ctl()EPOLLEXCLUSIVE를 설정해 뒀으면 이후 같은 epfd, fd 짝에 EPOLL_CTL_MOD를 하면 오류가 난다. eventsEPOLLEXCLUSIVE를 지정하고 대상 파일 디스크립터 fd에 epoll 인스턴스를 지정해서 epoll_ctl()을 호출하는 것 역시 실패하게 된다. 이 경우 모두에서 오류는 EINVAL이다.

EPOLLEXCLUSIVE 플래그는 epoll_ctl() 호출 시 event.events 필드에 입력하는 플래그다. 절대 epoll_wait(2)에서 반환되지 않는다.

RETURN VALUE

성공 시 epoll_ctl()은 0을 반환한다. 오류 발생 시 epoll_ctl()은 -1을 반환하며 오류를 나타내도록 errno를 설정한다.

ERRORS

EBADF
epfdfd가 유효한 파일 디스크립터가 아니다.
EEXIST
opEPOLL_CTL_ADD인데 제공된 파일 디스크립터 fd가 이미 그 epoll 인스턴스에 등록돼 있다.
EINVAL
epfdepoll 파일 디스크립터가 아니거나, fdepfd와 같거나, 요청한 동작 op를 이 인터페이스에서 지원하지 않는다.
EINVAL
eventsEPOLLEXCLUSIVE와 함께 유효하지 않은 이벤트 종류를 지정했다.
EINVAL
opEPOLL_CTL_MOD인데 eventsEPOLLEXCLUSIVE가 포함돼 있다.
EINVAL
opEPOLL_CTL_MOD인데 앞서 그 epfd, fd 짝에 EPOLLEXCLUSIVE 플래그가 적용되었다.
EINVAL
eventEPOLLEXCLUSIVE를 지정했는데 fd가 epoll 인스턴스를 가리킨다.
ELOOP
fd가 epoll 인스턴스를 가리키는데 이 EPOLL_CTL_ADD 동작으로 인해 epoll 인스턴스들이 서로를 감시하는 루프가 생기게 되거나 epoll 인스턴스 중첩 단계가 5보다 커진다.
ENOENT
opEPOLL_CTL_MODEPOLL_CTL_DEL인데 fd가 그 epoll 인스턴스에 등록돼 있지 않다.
ENOMEM
요청한 op 제어 동작을 처리하기에 충분한 메모리가 없다.
ENOSPC
epoll 인스턴스에 새 파일 디스크립터를 등록(EPOLL_CTL_ADD)하려는 중에 /proc/sys/fs/epoll/max_user_watches에 의한 제한에 걸렸다. 자세한 내용은 epoll(7) 참고.
EPERM
대상 파일 fdepoll을 지원하지 않는다. 예를 들어 fd가 정규 파일이나 디렉터리를 가리키면 이 오류가 발생할 수 있다.

VERSIONS

커널 버전 2.6에서 epoll_ctl()이 추가되었다. glibc 버전 2.3.2부터 라이브러리 지원을 제공한다.

CONFORMING TO

epoll_ctl()은 리눅스 전용이다.

NOTES

epoll 인터페이스는 poll(2)을 지원하는 파일 디스크립터들을 모두 지원한다.

BUGS

커널 버전 2.6.9 전에서는 EPOLL_CTL_DEL 동작에서 event를 무시하는데도 그 인자에 널 아닌 포인터가 있어야 했다. 리눅스 2.6.9부터는 EPOLL_CTL_DEL 이용 시 event에 NULL을 지정할 수 있다. 2.6.9 전 커널로 이식 가능해야 하는 응용에서는 event에 널 아닌 포인터를 지정해 주는 게 좋다.

flagsEPOLLWAKEUP을 지정했지만 호출자에게 CAP_BLOCK_SUSPEND 역능이 없는 경우에는 EPOLLWAKEUP 플래그가 조용히 무시된다. 이런 유감스런 동작 방식이 필요한 이유는 최초 구현에서 flags 인자의 유효성 검사를 수행하지 않았던 데다가, 검사를 해서 호출자가 CAP_BLOCK_SUSPEND 역능을 가지고 있지 않으면 호출이 실패하도록 EPOLLWAKEUP을 추가하면 하필 임의적으로 (그리고 불필요하게) 그 비트를 설정했기 때문에 동작에 문제가 생길 기존 사용자 공간 응용이 적어도 한 가지 있었기 때문이다. 따라서 견고한 응용이라면 EPOLLWAKEUP 플래그를 쓰려 할 때 CAP_BLOCK_SUSPEND 역능을 가지고 있는지 확실히 확인하는 게 좋다.

SEE ALSO

epoll_create(2), epoll_wait(2), poll(2), epoll(7)


2021-03-22