阅读本文之前请确保你看过上一篇文章:Libevent 源码阅读笔记(一)、从一个简单例子开始(上)
在上一篇文章中,我们提到了关于 Libevent 使用的一个基本逻辑:
- 调用
event_init()创建 event_base 对象,一个 event_base 对象相当于一个 Reactor 实例- 创建具体的事件处理器,其中
evsignal_new()创建的是信号事件处理器和evtimer_new()创建的是定时事件处理器- 调用
event_add()将事件处理器插入到注册事件队列中,并将其对应的事件插入到事件多路分发器中,相当于 Reactor 中的register_handler方法- 调用
event_base_dispatch()执行事件循环- 循环结束后,调用
*_free()释放系统资源
在这篇文章中,我们将继续分析剩余的后 3 个步骤
将事件处理器添加到注册事件队列中
要了解如何将事件处理器插入到注册事件队列中,就需要先知道 Libevent 是如何将句柄和注册事件之间的联系定义出来。其相关的数据结构主要定义在 event-internal.h 和 evmap.c 文件中
1 | //event-internal.h |
创建好的 event 事件可以利用 event_add()插入相应的注册事件队列中
1 | //向注册事件队列中添加事件处理器 |
可以看到,在整个 event_add_nolock_函数中,主要的工作是为不同的事件提供对应的操作,主要分为 3 类操作,
- 调用
evmap_io_add_将 I/O 事件添加到事件多路分发器中,并将对应的事件处理器添加到 I/O 事件队列当中,同时建立起 I/O 事件和 I/O 事件处理器之间的映射,最后将 I/O 事件处理器插入到注册事件队列中 - 调用
evmap_signal_add_将信号事件添加到事件多路分发器中,并将对应的事件处理器添加到信号事件队列当中,同时建立起信号事件和信号事件处理器之间的映射,最后将信号事件处理器插入到注册事件队列中 - 调用
event_queue_insert_inserted修改 event_base 的事件处理器总数 - 根据是否允许将定时器重新插入到通用定时器队列或时间堆中,调用
event_queue_reinsert_timeout和event_queue_insert_timeout来将定时器插入到通用定时器队列或时间堆中
接下来,对于注册事件,Libevent 通过evmap_io_add_、 evmap_signal_add_ 以及 event_queue_insert_inserted进行将它们插入到对应的事件队列当中,其中evmap_io_add_、 evmap_signal_add_ 被定义在 evmap.c 文件中,而event_queue_insert_inserted被定义在 event.c 文件中
1 | // evmap.c 文件 |
对于超时事件,Libevent 则调用了event_queue_insert_timeout来将定时器插入到通用定时器队列或时间堆。
1 | static void event_queue_insert_timeout(struct event_base *base, struct event *ev) |
这里需要指出,早期的 Libevent 使用了时间堆来设计定时器。由于在某些场合下,升序定时器链表的效率会更高,因此新版本的 Libevent 同时支持通用定时器链表和时间堆的操作。
Libevent 的核心动力 —— 事件循环
正如前面提到,Libevent 是基于事件驱动的,整个框架库的运转核心在于事件驱动:Reactor 在接收到相应事件后,通过 event_base_dispatch() 的方法,将事件分派给对应的事件处理器去处理。event_base_dispatch()定义在 event.c 文件中
1 | int event_base_dispatch(struct event_base *event_base) |
从代码中可以看出,event_base_dispatch()调用了event_base_loop(),而event_base_loop()的关键是
调用了 event_base 中的evsel->dispatch(),该方法封装了 I/O 复用系统调用。至于如何根据编程环境的不同,自动选择合适的 I/O 复用技术,可以看上一篇文章中关于 eventop 的介绍
释放资源
1 | static int event_base_free_queues_(struct event_base *base, int run_finalizers) |
参考资料
《Linux 高性能服务器编程》 —— 游双著
《libevent-book》 —— Libevent 上的官方文档
- 本文作者: Phoenix
- 本文链接: https://phoenix500526.github.io/2020/08/10/Libevent-源码阅读笔记-二-从一个简单例子开始-下/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!