Search

Under the Hood: Linux Epoll — 리눅스 커널 소스코드로 살펴보는 epoll의 내부 동작

URL
생성 일시
2026/04/06 00:06
최종 편집 일시
2026/04/06 00:06
태그
컴투스
파일과 미디어
개론 클라이언트의 요청을 처리하는 서버를 구축할 때는 일반적으로 TCP, UDP 프로토콜을 기반으로 통신을 처리한다. 이때 모든 네트워크 통신은 기본적으로 소켓(Socket)이라는 단위를 통해 관리된다. 아키텍처 관점에서 보면 하나의 프로세스 또는 스레드가 하나 이상의 소켓을 동시에 처리할 수 있다. 하지만 여러 소켓을 효율적으로 처리하려면 I/O Multiplexing(입출력 다중화) 메커니즘이 필요하다. 이를 통해 단일 스레드 또는 프로세스가 여러 I/O […] || 개론 클라이언트의 요청을 처리하는 서버를 구축할 때는 일반적으로 TCP, UDP 프로토콜을 기반으로 통신을 처리한다. 이때 모든 네트워크 통신은 기본적으로 소켓(Socket)이라는 단위를 통해 관리된다. 아키텍처 관점에서 보면 하나의 프로세스 또는 스레드가 하나 이상의 소켓을 동시에 처리할 수 있다. 하지만 여러 소켓을 효율적으로 처리하려면 I/O Multiplexing(입출력 다중화) 메커니즘이 필요하다. 이를 통해 단일 스레드 또는 프로세스가 여러 I/O 이벤트를 동시에 감시하고 처리할 수 있다. 리눅스에서는 이러한 입출력 다중화를 지원하기 위해 select, poll, epoll과 같은 API를 제공한다. 그중에서도 epoll은 대규모 동시 연결 환경에서 높은 효율을 제공하는 메커니즘으로 널리 사용된다. 이번 글에서는 epoll의 사용 방법 자체보다는 리눅스 커널 소스코드 관점에서 epoll이 내부적으로 어떻게 동작하는지를 살펴보려 한다. 특히 리눅스 커널 내부 구조와 데이터 흐름을 중심으로 epoll의 동작 과정을 단계적으로 분석한다. 주의 사항 커널 버전: 리눅스 커널 6.19.3 버전을 기준으로 설명하며, 타 버전과는 구현 세부 사항에서 차이가 있을 수 있다. 참고용 자료: 방대한 소스코드를 분석한 내용이므로 실제 커널의 모든 예외 처리를 담고 있지는 않다. 비교 배제: 본 글에서는 select나 poll과의 성능 비교보다는 epoll 자체의 내부 로직에 집중한다. 본론: epoll의 내부 동작 원리 epoll 인터페이스를 구성하는 syscall은 세 가지다. epoll_create, epoll_ctl, epoll_wait이다. 기본적인 소켓 서버에서 클라이언트 요청을 처리하는 흐름은 아래 다이어그램과 같다. 동작 순서를 간략히 설명하면 다음과 같다. epoll_create로 epoll 파일 디스크립터(epollfd)를 생성하고, epoll_ctl을 통해 관심 FD 목록에 원하는 소켓을 등록한다. 이후 해당 FD에 Read/Write 이벤트가 발생하면 epoll_wait syscall에 의해 블로킹 상태에서 깨어나며, 이벤트를 발생시킨 FD를 처리할 수 있게 된다. 지금부터 각 syscall을 순서대로 살펴보자. epoll_create SYSCALL_DEFINE1(epoll_create, int, size) { if (size <= 0) return -EINVAL; return do_epoll_create(0); } epoll_create syscall이 호출되면 내부적으로 do_epoll_create 함수가 실행된다. static int do_epoll_create(int flags) { [...] error = ep_alloc(&ep); [...] FD_PREPARE(fdf, O_RDWR | (flags & O_CLOEXEC), anon_inode_getfile("[eventpoll]", &eventpoll_fops, ep, O_RDWR | (flags & O_CLOEXEC))); [...] ep->file = fd_prepare_file(fdf); return fd_publish(fdf); } ep_alloc 함수는 struct eventpoll 구조체를 할당한다. anon_inode_getfile 함수는 하나의 파일 인스