关于epoll机制

世上本没有光,佛说要有光,于是便有了光,随即有了太阳。

行文思路:

  1. 概述epoll的设计思想
  2. 代码分析:
  3. 大致熟悉核心结构
  4. 从3个核心系统调用入手代码流程(同时深入对数据结构的理解)
  5. 分析几个重要函数
  6. 其他tech datails
  7. ET LT
  8. 惊群效应

设计思想

我们希望能实现下述功能:
进程睡眠,一批fd上某个fd有事件发生的时候,进程被唤醒来处理。

select/poll的设计逻辑:

  1. 将进程同时挂载到所有fd相关的睡眠队列上;
  2. 任意一个fd的底层机制有事件触发后都会唤醒该进程;
  3. 该进程被唤醒后,知道有事件发生了,但是不知道有什么事件发生在哪里,于是遍历所有的fd进行判断。

epoll的设计逻辑:

  1. 进程睡在一个专门的队列上;
  2. 往所有要监听的fd上挂一个函数,当这些fd底层有事件发生的时候,调用这个函数;
  3. 这个函数做两件事情:
  4. 将该fd加入到一个ready list中;
  5. 唤醒对应的进程;

小结:我们希望的是同一个进程能够同时监听多个fd,select/poll方式同时睡眠在所有fd的睡眠队列上;epoll方式选择睡眠在一个专门的队列上,同时向所有的fd挂载一个回调函数,在回调函数函数中完成一些更复杂的操作。

相关结构

//详细见fs/eventpoll.c注释, 最核心结构

/* eventpoll 对象,我们前文描述的专门的睡眠队列,ready list
这些per-eventpoll的结构都应该组织在这个结构中*/
struct eventpoll;

/* epoll机制监听的事件项,根据用户空间传递的信息,监听的fd,监听的事件组织起来的 */
struct epitem;

/* 挂载在sk_wq上用于被唤醒的结构,其中包含了一个重要的回调函数(ep_table_queue_proc)。*/
struct eppoll_entry;

这三个结构就能实现上述设计思想中的描述。更细节部分可以见参考。更好的是do not talk more, show me the code。

其他结构

epoll_event //显然

ep_pqueue
    一个临时量,用于将epitem结构与一个回调函数函数临时组织在一起。代码分析

从3个系统调用入手的的代码分析

  1. epoll_create
    epoll创建的eventpoll本身也要被纳入到vfs管理,epoll_create主要做两件事:
  • 创建struct eventpoll结构;
  • 将其纳入到vfs中管理(分配file接哦股,fd等)
  1. epoll_ctl(ADD)
    对于EPOLL_CTL_ADD是创建一个eppoll_entry结构,将其挂载到sk_wq上(当然是针对socket文件)。

  2. epoll_wait
    睡眠,然后被唤醒,ep_poll_callback()函数唤醒的。

重要函数

  1. ep_ptable_queue_proc()
    最重要的作用是往eppoll_entry结构上挂入ep_poll_callback()。后续又会将epoll_entry结构改到sk_wq等睡眠队列上,从而建立起sk_wq被唤醒的时候能够调用到epoll机制。

  2. ep_poll_callback()
    从sk_wq被唤醒的时候调用该函数,该函数可能通过ep_wq来唤醒调用ep_poll_wait睡眠的进程。

  3. ep_send_event_proc()
    epoll机制很多的重要逻辑都是在这个函数中实现的,譬如:oneshot, ET/LT逻辑等。
    在ep_send_events_proc()中,会检查epitem是不是oneshot模式的,如果是的,第一次唤醒还是正常处理的,但是会将epitem中监听的事件选项清0,那么后续唤醒的时候,执行ep_item_poll()获取监听事件的时候,就获取的是空事件的。即确保了该监听项的oneshot。至于监听项的删除与更改则依赖于EPOLL_CTL_MOD EPOLL_CTL_DEL命令了。

总结:ep_poll_callback() 以及 epoll_wait()的后半部分可以说是epoll机制各种逻辑的实现关键。特别是通过epoll_wait()进入的ep_send_events_proc()函数。
其他tech details

参考

https://blog.csdn.net/dog250/article/details/50528373
https://blog.csdn.net/qq_36347375/article/details/91177145
https://cloud.tencent.com/developer/article/1481046
https://www.jianshu.com/p/ca2992be4722

其他

  1. 某个entity的wait list上挂载的不仅仅是一个进程,而是一个wait entity。本质就是上面有一个回调函数,在被唤醒的时候去调用。调用这个函数可能会唤醒某个进程,也可能执行一些更复杂的操作。

  2. 在这里插入图片描述

  3. 事件含义分析
    解析各种事件含义,分析其是如何在epoll机制中实现的。

  4. EPOLLIN 可读事件,底层transport层触发,数据到来的时候,可以通过检查buffer触发。

  5. EPOLLOUT 可写事件,底层的transport层触发,但是没有很清楚是由谁来触发唤醒操作的。在不可写到可写的转变时刻会触发,是边缘触发类型的。

  6. EPOLLRDHUP 对端断开连接

  7. EPOLLPRI 有带外数据到来

  8. EPOLLERR 发生错误

  9. EPOLLHUP 文件描述符被挂断
    //上述6种事件的触发,根据具体情况是不同的,我们可以自己选择。自己在传输层判断事件,自己触发。一般来说,我们使用sock sk中的一些函数就可以进行唤醒事件触发操作。sk->sk_data_ready(), sk->sk_write_space()等函数。详情要见各种不同的域:譬如TCP域。参见https://cloud.tencent.com/developer/article/1481046。

  10. EPOLLET 边缘触发

  11. EPOLLONESHOT 只监听一次,阅读源码已经清楚这个机制了
    //ET与ONESHOT逻辑都是在ep_send_events_proc()逻辑中实现的。详情见源码注释

  12. EPOLLWAKEUP 与系统的电源管理自动睡眠有关
    //EPOLLWAKEUP还不清楚,与系统自动休眠有关。

  13. EPOLLEXCLUSIVE 避免惊群问题。在ep_epoll_callback()中实现了该机制的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值