[内核源码]epoll实现原理
这篇文章围绕 Linux epoll 做了完整源码走读,从使用接口、事件语义到内核数据结构与关键函数调用链,重点解释 ET/LT 与回调唤醒机制。入口与问题背景以“ET/LT 在源码中如何实现”为核心问题,建立阅读主线。先交代 epoll_create、epoll_ctl、epoll_wait 三个用户态接口职责。将业…
文章主要对 tcp 通信进行 epoll 源码走读。 引发我对 epoll 源码感兴趣的原因在于知乎上的一个提问,ET和LT模式在源码中到底怎么实现的 Linux 源码:Linux 5.7 版本。epoll 核心源码:eventpoll.h / eventpoll.c。 搭建 epoll 内核调试环境视频:vscode + gdb 远程调试 linux (EPOLL) 内核源码1. 应用场景 epoll 应用,适合海量用户,一个时间段内部分活跃的用户群体。 例如 app,正常用户并不是 24 小时都拿起手机玩个不停,可能玩一下,又去干别的事,回头又玩一下,断断续续地操作。即便正在使用 app 也不是连续产生读写通信事件,可能手指点击几下页面,页面产生需要的内容,用户就去浏览内容,不再操作了。换句话说,在海量用户里,同一个时间段内,很可能只有一小部分用户正在活跃,而在这一小部分活跃用户里,又只有一小撮人同时点击页面上的操作。那 epoll 管理海量用户,只需要将这一小撮人产生的事件,及时通知 appserver 处理逻辑即可。2. 预备知识走读 epoll 源码前,先熟悉内核相关工作流程:[epoll 源码走读] epoll 源码实现-预备知识。走读源码过程中,可以通过 Linux 文档 搜索 epoll 相关知识。3. 使用接口。 | 接口 | 描述 | | :----------------------------------------------------------- | :-------------------------------------------------- | | epoll_create | 创建 epoll。 | | epoll_ctl | fd 事件注册函数,用户通过这个函数关注 fd 读写事件。 | | epoll_wait | 阻塞等待 fd 事件发生。 |使用流程。 img 图片来源:《epoll 多路复用 I/O工作流程》4. 事件 常用事件注释可以请参考 epoll_ctl 文档。// eventpoll.h #define EPOLLIN (__force __poll_t)0x00000001 #define EPOLLOUT (__force __poll_t)0x00000004 #define EPOLLERR (__force __poll_t)0x00000008 #define EPOLLHUP (__force __poll_t)0x00000010 #define EPOLLRDHUP (__force __poll_t)0x00002000 #define EPOLLEXCLUSIVE ((__force __poll_t)(1U << 28)) #define EPOLLET ((__force __poll_t)(1U << 31)) | 事件 | 描述 | | :------------- | :----------------------------------------------------------- | | EPOLLIN | 有可读数据到来。 | | EPOLLOUT | 有数据要写。 | | EPOLLERR | 该文件描述符发生错误。 | | EPOLLHUP | 该文件描述符被挂断。常见 socket 被关闭(read == 0)。 | | EPOLLRDHUP | 对端已关闭链接,或者用 shutdown 关闭了写链接。 | | EPOLLEXCLUSIVE | 唯一唤醒事件,主要为了解决 epoll_wait 惊群问题。多线程下多个 epoll_wait 同时等待,只唤醒一个 epoll_wait 执行。 该事件只支持 epoll_ctl 添加操作 EPOLL_CTL_ADD。 | | EPOLLET | 边缘触发模式。 | 通过 tcp_poll 函数,可以看到 socket 事件对应的相关事件逻辑。// tcp.c /* * Wait for a TCP event. * * Note that we don't need to lock the socket, as the upper poll layers * take care of normal races (between the test and the event) and we don't * go look at any of the socket buffers directly. */ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait) { __poll_…
正在初始化 WebAssembly 引擎…
首次编译原生模块可能需要数秒
就绪后,页面交互将以接近原生的速度运行