a scalable I/O event notification mechanism used in Linux programming to efficiently monitor multiple file descriptors to see if I/O is possible on any of them.
(The more recent epoll_create1(2) extends the functionality of epoll_create(2).)

  • epoll 现在是线程安全的,而 select 和 poll 不是。
  • epoll 基于事件驱动,epoll_ctl 注册事件并注册 callback 回调函数,epoll_wait 只返回发生的事件避免了像 select 和 poll 对事件的整个轮寻操作。
#include <stdio.h>     // for fprintf()
#include <unistd.h>    // for close(), read()
#include <sys/epoll.h> // for epoll_create1(), epoll_ctl(), struct epoll_event
#include <string.h>    // for strncmp
 
int main()
{
	int running = 1, event_count, i;
	size_t bytes_read;
	char read_buffer[READ_SIZE + 1];
	struct epoll_event event, events[MAX_EVENTS];
	int epoll_fd = epoll_create1(0);
 
	if (epoll_fd == -1) {
		fprintf(stderr, "Failed to create epoll file descriptor\n");
		return 1;
	}
 
	event.events = EPOLLIN;
	event.data.fd = 0;
 
	if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, 0, &event))
	{
		fprintf(stderr, "Failed to add file descriptor to epoll\n");
		close(epoll_fd);
		return 1;
	}
 
	while (running) {
		printf("\nPolling for input...\n");
		event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, 30000);
		printf("%d ready events\n", event_count);
		for (i = 0; i < event_count; i++) {
			printf("Reading file descriptor '%d' -- ", events[i].data.fd);
			bytes_read = read(events[i].data.fd, read_buffer, READ_SIZE);
			printf("%zd bytes read.\n", bytes_read);
			read_buffer[bytes_read] = '\0';
			printf("Read '%s'\n", read_buffer);
		
			if(!strncmp(read_buffer, "stop\n", 5))
			running = 0;
		}
	}
 
	if (close(epoll_fd)) {
		fprintf(stderr, "Failed to close epoll file descriptor\n");
		return 1;
	}
 
	return 0;
}

Level-triggered and edge-triggered

水平触发 (level-trggered)

  • 只要文件描述符关联的读内核缓冲区非空,有数据可以读取,就一直发出可读信号进行通知,
  • 当文件描述符关联的内核写缓冲区不满,有空间可以写入,就一直发出可写信号进行通知

边缘触发 (edge-triggered)

  • 当文件描述符关联的读内核缓冲区由空转化为非空的时候,则发出可读信号进行通知,
  • 当文件描述符关联的内核写缓冲区由满转化为不满的时候,则发出可写信号进行通知
  • kqueue for macos/bsd