2025-11-27 · libevent
【Libevent 深度剖析与实战指南】事件结构体 (struct event)
解剖 Libevent 的基本原子——struct event,理解其内部字段、状态流转与生命周期。
在 Libevent 中,event_base 是 Reactor
模式的核心实例,而 event_base_loop
则是驱动整个系统的引擎。本篇我们将深入源码(基于
2.1.12-stable),揭开它们的神秘面纱。
event_base: Reactor 的载体struct event_base
是一个不透明的结构体(Opaque Struct),其定义在
event-internal.h 中。它维护了 Reactor
运行所需的所有状态。
struct event_base {
// 1. 后端引擎 (Backend)
const struct eventop *evsel; // 当前使用的后端接口 (如 epollops)
void *evbase; // 后端特定的数据 (如 epoll_fd)
// 2. 事件队列
struct event_list *activequeues; // 激活队列数组 (按优先级划分)
int nactivequeues; // 优先级数量
// 3. 注册事件管理
struct event_io_map io; // IO 事件映射表 (fd -> event)
struct event_signal_map sigmap; // 信号事件映射表
struct min_heap timeheap; // 定时器最小堆
// 4. 控制标志
int event_gotterm; // 是否收到 loopexit 指令
int event_break; // 是否收到 loopbreak 指令
// ... 其他字段 (线程锁、通知管道等)
};通常我们使用 event_base_new()
创建默认实例。如果需要定制(例如禁用 epoll 强制使用
poll),则需要使用 event_config。
struct event_config *cfg = event_config_new();
// 避免使用 epoll
event_config_avoid_method(cfg, "epoll");
// 要求后端支持 Edge-Triggered 模式
event_config_require_features(cfg, EV_FEATURE_ET);
struct event_base *base = event_base_new_with_config(cfg);
event_config_free(cfg);event_base_loop: 永不停歇的引擎event_base_dispatch(base) 实际上只是
event_base_loop(base, 0) 的封装。真正的逻辑在
event_base_loop 中。
int event_base_loop(struct event_base *base, int flags) {
// ... 初始化与锁 ...
while (!done) {
// 1. 检查是否需要立即停止
if (base->event_gotterm) {
break;
}
// 2. 计算后端等待时间 (Timeout)
// 从最小堆中取出最近的一个定时器时间
tv_p = &tv;
if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {
timeout_next(base, &tv_p);
} else {
// 如果有激活事件,或者是非阻塞模式,则不等待
evutil_timerclear(&tv);
}
// 3. 调用后端 (Backend Dispatch)
// 例如调用 epoll_wait,将就绪的 fd 对应的 event 插入激活队列
res = base->evsel->dispatch(base, tv_p);
// 4. 处理超时事件
timeout_process(base);
// 5. 处理激活队列 (Process Active Events)
if (base->event_count_active) {
event_process_active(base);
} else if (flags & EVLOOP_ONCE) {
// 如果是 EVLOOP_ONCE 模式且没有事件被激活,则退出
done = 1;
}
}
// ... 清理 ...
return 0;
}epoll_wait 的超时时间。如果堆顶定时器是 50ms
后触发,那么 epoll_wait 最多等待 50ms。epoll_wait 返回时,Libevent 会遍历就绪的
fd,找到对应的 struct event,将其状态设置为
EVLIST_ACTIVE,并插入到
activequeues 中。activequeues,依次调用用户的回调函数。注意,这里是同步调用。如果回调函数执行时间过长,会阻塞下一轮循环。Libevent 提供了两种停止循环的方法,区别在于即时性:
event_base_loopexit(base, tv):event_gotterm 标志。tv。event_base_loopbreak(base):event_break 标志。event_base 是 Libevent 的状态容器,而
event_base_loop
是驱动状态流转的动力源。理解了这个循环,你就理解了 Reactor
模式的本质:计算等待时间 -> 阻塞等待 ->
激活事件 -> 处理回调。
下一篇,我们将深入 Layer 1,看看 epoll
等后端是如何被封装成统一接口 eventop 的。
上一篇: 00-intro/build-systems.md - 多构建工具链集成 下一篇: 01-core/backend-epoll.md - IO 多路复用层详解
把当前热点继续串成多页阅读,而不是停在单篇消费。
2025-11-27 · libevent
解剖 Libevent 的基本原子——struct event,理解其内部字段、状态流转与生命周期。
2025-11-27 · libevent
解密 Libevent 如何封装 epoll、kqueue 等底层机制,实现跨平台的统一事件接口。
2025-11-27 · libevent
对比 Linux epoll、BSD kqueue 和 Windows IOCP 的异同,以及 Libevent 在不同平台上的实现差异与避坑指南。
2025-11-27 · libevent
告别手写 gcc 命令,详解如何在 Makefile、CMake 和 Bazel 项目中优雅地集成 Libevent。
在 Libevent 中,event_base 是 Reactor
模式的核心实例,而 event_base_loop
则是驱动整个系统的引擎。本篇我们将深入源码(基于
2.1.12-stable),揭开它们的神秘面纱。
event_base: Reactor 的载体struct event_base
是一个不透明的结构体(Opaque Struct),其定义在
event-internal.h 中。它维护了 Reactor
运行所需的所有状态。
struct event_base {
// 1. 后端引擎 (Backend)
const struct eventop *evsel; // 当前使用的后端接口 (如 epollops)
void *evbase; // 后端特定的数据 (如 epoll_fd)
// 2. 事件队列
struct event_list *activequeues; // 激活队列数组 (按优先级划分)
int nactivequeues; // 优先级数量
// 3. 注册事件管理
struct event_io_map io; // IO 事件映射表 (fd -> event)
struct event_signal_map sigmap; // 信号事件映射表
struct min_heap timeheap; // 定时器最小堆
// 4. 控制标志
int event_gotterm; // 是否收到 loopexit 指令
int event_break; // 是否收到 loopbreak 指令
// ... 其他字段 (线程锁、通知管道等)
};通常我们使用 event_base_new()
创建默认实例。如果需要定制(例如禁用 epoll 强制使用
poll),则需要使用 event_config。
struct event_config *cfg = event_config_new();
// 避免使用 epoll
event_config_avoid_method(cfg, "epoll");
// 要求后端支持 Edge-Triggered 模式
event_config_require_features(cfg, EV_FEATURE_ET);
struct event_base *base = event_base_new_with_config(cfg);
event_config_free(cfg);event_base_loop: 永不停歇的引擎event_base_dispatch(base) 实际上只是
event_base_loop(base, 0) 的封装。真正的逻辑在
event_base_loop 中。
int event_base_loop(struct event_base *base, int flags) {
// ... 初始化与锁 ...
while (!done) {
// 1. 检查是否需要立即停止
if (base->event_gotterm) {
break;
}
// 2. 计算后端等待时间 (Timeout)
// 从最小堆中取出最近的一个定时器时间
tv_p = &tv;
if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {
timeout_next(base, &tv_p);
} else {
// 如果有激活事件,或者是非阻塞模式,则不等待
evutil_timerclear(&tv);
}
// 3. 调用后端 (Backend Dispatch)
// 例如调用 epoll_wait,将就绪的 fd 对应的 event 插入激活队列
res = base->evsel->dispatch(base, tv_p);
// 4. 处理超时事件
timeout_process(base);
// 5. 处理激活队列 (Process Active Events)
if (base->event_count_active) {
event_process_active(base);
} else if (flags & EVLOOP_ONCE) {
// 如果是 EVLOOP_ONCE 模式且没有事件被激活,则退出
done = 1;
}
}
// ... 清理 ...
return 0;
}epoll_wait 的超时时间。如果堆顶定时器是 50ms
后触发,那么 epoll_wait 最多等待 50ms。epoll_wait 返回时,Libevent 会遍历就绪的
fd,找到对应的 struct event,将其状态设置为
EVLIST_ACTIVE,并插入到
activequeues 中。activequeues,依次调用用户的回调函数。注意,这里是同步调用。如果回调函数执行时间过长,会阻塞下一轮循环。Libevent 提供了两种停止循环的方法,区别在于即时性:
event_base_loopexit(base, tv):event_gotterm 标志。tv。event_base_loopbreak(base):event_break 标志。event_base 是 Libevent 的状态容器,而
event_base_loop
是驱动状态流转的动力源。理解了这个循环,你就理解了 Reactor
模式的本质:计算等待时间 -> 阻塞等待 ->
激活事件 -> 处理回调。
下一篇,我们将深入 Layer 1,看看 epoll
等后端是如何被封装成统一接口 eventop 的。
上一篇: 00-intro/build-systems.md - 多构建工具链集成 下一篇: 01-core/backend-epoll.md - IO 多路复用层详解
把当前热点继续串成多页阅读,而不是停在单篇消费。
2025-11-27 · libevent
解剖 Libevent 的基本原子——struct event,理解其内部字段、状态流转与生命周期。
2025-11-27 · libevent
解密 Libevent 如何封装 epoll、kqueue 等底层机制,实现跨平台的统一事件接口。
2025-11-27 · libevent
对比 Linux epoll、BSD kqueue 和 Windows IOCP 的异同,以及 Libevent 在不同平台上的实现差异与避坑指南。
2025-11-27 · libevent
告别手写 gcc 命令,详解如何在 Makefile、CMake 和 Bazel 项目中优雅地集成 Libevent。