NAME

epoll_wait, epoll_pwait, epoll_pwait2 - epoll 파일 디스크립터에서 I/O 이벤트 기다리기

SYNOPSIS

#include <sys/epoll.h>

int epoll_wait(int epfd, struct epoll_event *events,
               int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events,
               int maxevents, int timeout,
               const sigset_t *sigmask);
int epoll_pwait2(int epfd, struct epoll_event *events,
               int maxevents, const struct timespec *timeout,
               const sigset_t *sigmask);

DESCRIPTION

epoll_wait() 시스템 호출은 파일 디스크립터 epfd가 가리키는 epoll(7) 인스턴스에서 이벤트를 기다린다. events가 가리키는 버퍼를 이용해 뭔가 이벤트가 있는 관심 목록의 파일 디스크립터들에 대한 준비 목록의 정보를 반환한다. 최대 maxevents 개 이벤트를 반환한다. maxevents 인자는 0보다 커야 한다.

timeout 인자는 epoll_wait()에서 블록할 밀리초 수를 나타낸다. CLOCK_MONOTONIC 클럭으로 시간을 측정한다.

다음 어느 경우든 해당할 때까지 epoll_wait() 호출이 블록하게 된다.

참고로 timeout 시간을 시스템 클럭 해상도에 따라 올림하게 되며 커널 스케줄링 지연도 있기 때문에 그 블록 시간을 약간 넘길 수도 있다. timeout을 -1로 지정하면 epoll_wait()이 무한정 블록하게 되며, timeout을 0으로 지정하면 가용 이벤트가 없더라도 epoll_wait()이 즉시 반환하게 된다.

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_ctl(2)(EPOLL_CTL_ADD, EPOLL_CTL_MOD)에서 지정한 것과 동일한 데이터가 담겨 있다.

events 필드는 해당 열린 파일 기술 항목에 발생한 이벤트들을 나타내는 비트 마스크다. 이 마스크에 등장할 수 있는 비트들의 목록은 epoll_ctl(2)을 보라.

epoll_pwait()

epoll_wait()epoll_pwait()의 관계는 select(2)pselect(2)의 관계와 비슷하다. pselect(2)처럼 응용에서 epoll_pwait()을 사용해 파일 디스크립터가 준비 상태가 되거나 시그널을 잡을 때까지 안전하게 대기할 수 있다.

다음 epoll_pwait() 호출은

ready = epoll_pwait(epfd, &events, maxevents, timeout, &sigmask);

다음 호출들을 원자적으로 실행하는 것과 동등하다.

sigset_t origmask;

pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
ready = epoll_wait(epfd, &events, maxevents, timeout);
pthread_sigmask(SIG_SETMASK, &origmask, NULL);

sigmask 인자를 NULL로 지정할 수 있으며, 그 경우 epoll_pwait()epoll_wait()과 동등하다.

epoll_pwait2()

epoll_pwait2()timeout 인자를 빼면 epoll_pwait()과 동등하다. timespec 타입으로 인자를 받으므로 나노초 해상도로 타임아웃을 지정할 수 있다. 이 인자는 pselect(2)ppoll(2)에서과 똑같이 동작한다. timeout이 NULL이면 epoll_pwait2()가 무한정 블록할 수 있다.

RETURN VALUE

성공 시 epoll_wait()은 요청된 I/O를 할 준비가 된 파일 디스크립터 수를 반환하며, 지정한 timeout 밀리초 동안 준비된 파일 디스크립터가 없으면 0을 반환한다. 오류 시 epoll_wait()은 -1을 반환하며 오류를 나타내도록 errno를 설정한다.

ERRORS

EBADF
epfd가 유효한 파일 디스크립터가 아니다.
EFAULT
events가 가리키는 메모리 영역이 쓰기 권한으로 접근 가능하지 않다.
EINTR
(1) 요청된 이벤트가 하나라도 발생하거나 (2) timeout이 만료하기 전에 호출이 시그널 핸들러에 의해 중단되었다. signal(7) 참고.
EINVAL
epfdepoll 파일 디스크립터가 아니거나, maxevents가 0보다 작거나 같다.

VERSIONS

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

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

리눅스 커널 5.11에서 epoll_pwait2()가 추가되었다.

CONFORMING TO

epoll_wait(), epoll_pwait(), epoll_pwait2()는 리눅스 전용이다.

NOTES

한 스레드가 epoll_wait() 호출에서 블록돼 있는 동안 다른 스레드에서 그 epoll 인스턴스에 파일 디스크립터를 추가하는 게 가능하다. 새 파일 디스크립터가 준비 상태가 되면 epoll_wait() 호출의 블록이 풀리게 된다.

epoll_wait() 호출 시 maxevents 개를 넘는 파일 디스크립터가 준비 상태면 이어지는 epoll_wait() 호출에서 준비 상태인 파일 디스크립터들을 라운드 로빈으로 처리하게 된다. 이 동작은 프로세스에서 준비 상태라고 알고 있는 파일 디스크립터들에 집중하느라 준비 상태인 파일 디스크립터가 더 있다는 걸 알아채지 못해서 발생하는 기아 상황을 피하는 데 도움이 된다.

참고로 현재 관심 목록이 비어 있는 (또는 다른 스레드에서 파일 디스크립터를 닫거나 관심 목록에서 제거해서 관심 목록이 비게 되는) epoll 인스턴스에도 epoll_wait() 호출이 가능하다. 이후 (다른 스레드에서) 관심 목록에 어떤 파일 디스크립터를 추가하고 그 파일 디스크립터가 준비 상태가 될 때까지 호출이 블록하게 된다.

BUGS

커널 2.6.37 전에서는 timeout 값이 약 LONG_MAX / HZ 밀리초보다 크면 -1으로 (즉 무한으로) 처리한다. 그래서 가령 sizeof(long)이 4이고 커널 HZ 값이 1000인 시스템이라면 35.79 분보다 큰 타임아웃을 무한으로 처리한다.

C 라이브러리/커널 차이

진짜 epoll_pwait()epoll_pwait2() 시스템 호출에는 여섯 번째 인자 size_t sigsetsize가 있는데, 이는 sigmask 인자의 바이트 단위 크기를 나타낸다. glibc의 epoll_pwait() 래퍼 함수에서 이 인자를 고정된 값(sizeof(sigset_t))으로 지정한다.

SEE ALSO

epoll_create(2), epoll_ctl(2), epoll(7)


2021-03-22