epoll监听文件_Epoll的简介及原理

epoll 全称 eventpoll,是 linux 内核实现IO多路复用(IO multiplexing)的一个实现。IO多路复用的意思是在一个操作里同时监听多个输入输出源,在其中一个或多个输入输出源可用的时候返回,然后对其的进行读写操作。

在 linux 中,和 epoll 类似的有 select 和 poll。网上很多文章着重关注 epoll 与 select 的区别,或者关注 epoll 中 level-triggered 和 edge-triggered 的行为。

epoll 和 select

有不少文章里列出的 epoll 和 select 的区别不够准确,甚至中文维基百科里 select 复杂度 O(n),epoll 复杂度 O(log n) 的说法是错的。epoll 和 select 的主要区别是:

epoll 监听的 fd(file descriptor)集合是常驻内核的,它有 3 个系统调用 (epoll_create, epoll_wait, epoll_ctl),通过 epoll_wait 可以多次监听同一个 fd 集合,只返回可读写那部分

select 只有一个系统调用,每次要监听都要将其从用户态传到内核,有事件时返回整个集合。

从性能上看,如果 fd 集合很大,用户态和内核态之间数据复制的花销是很大的,所以 select 一般限制 fd 集合最大1024。

从使用上看,epoll 返回的是可用的 fd 子集,select 返回的是全部,哪些可用需要用户遍历判断。

尽管如此,epoll 的性能并不必然比 select 高,对于 fd 数量较少并且 fd IO 都非常繁忙的情况 select 在性能上有优势。

level-triggered 和 edge-triggered

关于 level-triggered 和 edge-triggered,Linux man page (epoll(7): I/O event notification facility) 已经讲得很明白了。

epoll 的原理

pollable

首先,linux 的 file 有个 pollable 的概念,只有 pollable 的 file 才可以加入到 epoll 和 select 中。一个 file 是 pollable 的当且仅当其定义了 file->f_op->pollfile->f_op->poll 的形式如下

__poll_t poll(struct file *fp, poll_table *wait)

不同类型的 file 实现不同,但做的事情都差不多:

  1. 通过 fp 拿到其对应的 waitqueue
  2. 通过 wait 拿到外部设置的 callback[[1]]
  3. 执行 callback(fp, waitqueue, wait),在 callback 中会将另外一个 callback2[[2]] 注册到 waitqueue[[3]]中,此后 fp 有触发事件就会调用 callback2

waitqueue 是事件驱动的,与驱动程序密切相关,简单来说 poll 函数在 file 的触发队列中注册了个 callback, 有事件发生时就调用callback。感兴趣可以根据文后 [[4]] 的提示看看 socket 的 poll 实现

了解了 pollable 我们看看 epoll 的三个系统调用 epoll_create, epoll_ctl, epoll_wait

epoll_create 只是在内核初始化一下数据结构然后返回个 fd

epoll_ctl 支持添加移除 fd,我们只看添加的情况。epoll_ctl 的主要操作在 ep_insert, 它做了以下事情:

  1. 初始化一个 epitem,里面包含 fd,监听的事件,就绪链表,关联的 epoll_fd 等信息
  2. 调用 ep_item_poll(epitem, ep_ptable_queue_proc[[1]])ep_item_poll 会调用 vfs_pollvfs_poll 会调用上面说的 file->f_op->pollep_poll_callback[[2]] 注册到 waitqueue
  3. 调用 ep_rbtree_insert(eventpoll, epitem)epitem 插入 evenpoll 对象的红黑树,方便后续查找

ep_poll_callback

在了解 epoll_wait 之前我们还需要知道 ep_poll_callback 做了哪些操作

  1. ep_poll_callback 被调用,说明 epoll 中某个 file 有了新事件
  2. eventpoll 对象有一个 rdllist 字段,用链表存着当前就绪的所有 epitem
  3. ep_poll_callback 被调用的时候将 file 对应的 epitem 加到 rdllist 里(不重复)
  4. 如果当前用户正在 epoll_wait 阻塞状态 ep_poll_callback 还会通过 wake_up_lockedepoll_wait 唤醒

epoll_wait 主要做了以下操作:

  1. 检查 rdllist,如果不为空则去到 7,如果为空则去到 2
  2. 设置 timeout
  3. 开始无限循环
  4. 设置线程状态为 TASK_INTERRUPTIBLE [参看 Sleeping in the Kernal](Kernel Korner - Sleeping in the Kernel)
  5. 检查 rdllist 如果不为空去到 7, 否则去到 6
  6. 调用 schedule_hrtimeout_range 睡到 timeout,中途有可能被 ep_poll_callback 唤醒回到 4,如果真的 timeout 则 break 去到 7
  7. 设置线程状态为 TASK_RUNNING,rdllist如果不为空时退出循环,否则继续循环
  8. 调用 ep_send_eventsrdllist 返回给用户态

epoll 的原理基本上就这些,还有很多细节如红黑树在哪里用,怎样实现 level-triggered 和 edge-triggered... 我还没看。

PS. 普通文件不是 pollable 的,详情请看 epoll_does_not_work_with_file

附录,以下列出的目录都是 linux 源码目录

  • [[1]] 对应 /fs/eventpoll.c 中的 ep_ptable_queue_proc
  • [[2]] 对应 /fs/evenpoll.c 中的 ep_poll_callback
  • [[3]] 通过 add_wait_queue 函数
  • [[4]] /linux/net/sock.csock_poll 是 socket 的 poll 实现,里面最后一步 sock->ops->poll() 对不同设备(比如蓝牙,以太网)不一样,大多会调用 /linux/net/core/datagram.c 里的 datagram_poll 然后去到 /linux/include/net/sock.h 中的 sock_poll_wait 然后去到 /linux/include/linux/poll.h 中的 poll_waitpoll_wait 其实只是调用一下 callback
  • [[5]] /linux/include/linux/poll.h 中的 vfs_poll
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
<p> <strong><span style="font-size:20px;color:#FF0000;">本课程主要针对计算机相关专业正在做毕设学生与需要项目实战练习Java学习者</span></strong> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">1. 包含:<span style="color:#FFFF00;background-color:#FF0000;">项目源码、</span><span style="color:#FFFF00;background-color:#FF0000;">项目文档、数据库脚本、软件工具</span>等所有资料</span></strong></span> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">2. 手把手带你从零开始部署运行本套系统</span></strong></span> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">3. 该项目附带源码资料可作为毕设使用</span></strong></span> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">4. 提供技术答疑和远程协助指导</span></strong></span><strong><span style="font-size:18px;"></span></strong> </p> <p> <br /> </p> <p> <span style="font-size:18px;"><strong>项目运行截图:</strong></span> </p> <p> <strong><span style="font-size:18px;">1)系统登陆界面</span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241015433522.png" alt="" /><br /> </span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">2)学生模块</span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241015575966.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">3)教师模块</span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241016127898.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">4)系统管理员</span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241016281177.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241016369884.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><br /> </span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">更多Java毕设项目请关注我毕设系列课程 <a href="https://edu.csdn.net/lecturer/2104">https://edu.csdn.net/lecturer/2104</a></span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><br /> </span></strong> </p>
<p> 课程演示环境:Windows10  </p> <p> 需要学习<span>Ubuntus</span>系统<span>YOLOv4-tiny</span>同学请前往《<span>YOLOv4-tiny</span>目标检测实战:训练自己数据集》 <span></span> </p> <p> <span> </span> </p> <p> <span style="color:#E53333;">YOLOv4-tiny</span><span style="color:#E53333;">来了!速度大幅提升!</span><span></span> </p> <p> <span> </span> </p> <p> <span>YOLOv4-tiny</span>在<span>COCO</span>上性能可达到:<span>40.2% AP50, 371 FPS (GTX 1080 Ti)</span>。相较于<span>YOLOv3-tiny</span>,<span>AP</span>和<span>FPS</span>性能有巨大提升。并且,<span>YOLOv4-tiny</span>权重文件只有<span>23MB</span>,适合在移动端、嵌入式设备、边缘计算设备上部署。<span></span> </p> <p> <span> </span> </p> <p> 本课程将手把手地教大家使用<span>labelImg</span>标注和使用<span>YOLOv4-tiny</span>训练自己数据集。课程实战分为两个项目:单目标检测(足球目标检测)和多目标检测(足球和梅西同时检测)。<span></span> </p> <p> <span> </span> </p> <p> 本课程<span>YOLOv4-tiny</span>使用<span>AlexAB/darknet</span>,在<span>Windows10</span>系统上做项目演示。包括:<span>YOLOv4-tiny</span>网络结构、安装<span>YOLOv4-tiny</span>、标注自己数据集、整理自己数据集、修改配置文件、训练自己数据集、测试训练出网络模型、性能统计<span>(mAP</span>计算<span>)</span>和先验框聚类分析。 <span> </span> </p> <p> <span> </span> </p> <p> 除本课程《<span>Windows</span>版<span>YOLOv4-tiny</span>目标检测实战:训练自己数据集》外,本人推出了有关<span>YOLOv4</span>目标检测系列课程。请持续关注该系列其它视频课程,包括:<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:训练自己数据集》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:人脸口罩佩戴识别》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:中国交通标志识别》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测:原理与源码解析》<span></span> </p> <p> <span> <img alt="" src="https://img-bss.csdnimg.cn/202007061503586145.jpg" /></span> </p> <p> <span><img alt="" src="https://img-bss.csdnimg.cn/202007061504169339.jpg" /><br /> </span> </p>
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页