epoll 多路复用驱动是异步事件处理,在用户层它提供了用户数据(epoll_data),方便事件触发后回调给用户处理。
文章来源 🔥:《深入理解 epoll 回调用户数据》
- glibc
/* sys/epoll.h */
typedef union epoll_data
{
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event
{
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
} __EPOLL_PACKED;
- 内核
/* eventpoll.h */
struct epoll_event {
__poll_t events;
__u64 data;
} EPOLL_PACKED;
- content
{:toc}
1. epoll_data
我们来看看 epoll 事件和接口,epoll_data 是用户数据,内核并不会处理,只与对应的 fd 绑定,当 fd 产生事件后,epoll_wait 会回调回来。
/* 用户数据。*/
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
/* 事件。 */
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
} __EPOLL_PACKED;
/* 事件控制接口。 */
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
/* 事件监控回调接口 */
int epoll_wait(int epfd, struct epoll_event* events, int maxevents. int timeout);
2. 内核
走读 epoll 源码,简单走一下 epoll 事件的添加和回调流程。
2.1. epoll_ctl
监控的 fd 事件信息,被添加到内核红黑树节点进行监控。
/* eventpoll.c */
SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event __user *, event) {
struct epoll_event epds;
if (ep_op_has_event(op) &&
copy_from_user(&epds, event, sizeof(struct epoll_event)))
return -EFAULT;
return do_epoll_ctl(epfd, op, fd, &epds, false);
}
int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds, bool nonblock) {
...
switch (op) {
case EPOLL_CTL_ADD:
if (!epi) {
epds->events |= EPOLLERR | EPOLLHUP;
error = ep_insert(ep, epds, tf.file, fd, full_check);
}
...
}
...
}
static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
struct file *tfile, int fd, int full_check

本文深入剖析了epoll的epoll_data用户数据在内核与用户层的角色,以及epoll_ctl和epoll_wait的处理流程。在用户层,epoll_data用于回调事件给用户处理,可以是fd、指针或其他类型。通过对比libco、redis、libev和nginx等开源项目的实现,探讨了不同参数传递方式的优缺点。最后强调了在实现事件驱动逻辑时需要考虑的细节和潜在问题。
最低0.47元/天 解锁文章
2006

被折叠的 条评论
为什么被折叠?



