在 Libevent 的世界里,一切皆事件。无论是网络
I/O、定时器还是信号,最终都被封装成一个
struct event
对象。本篇我们将深入这个结构体的内部,看看它是如何工作的。
1. 结构体定义
虽然在 event.h 中 struct event
被声明为不透明的,但在 event_struct.h
(或源码中的 event-internal.h)
中我们可以看到它的真面目。
struct event {
// 1. 回调相关
struct event_callback ev_evcallback;
// 2. 链表节点 (用于插入各种队列)
union {
TAILQ_ENTRY(event) ev_next_with_common_timeout;
int min_heap_idx;
} ev_timeout_pos;
evutil_socket_t ev_fd;
// 3. 所属的 Reactor
struct event_base *ev_base;
// 4. 事件相关
union {
// 用于 I/O 事件链表
struct {
TAILQ_ENTRY(event) ev_io_next;
struct timeval ev_timeout;
} ev_io;
// 用于信号事件链表
struct {
TAILQ_ENTRY(event) ev_signal_next;
short ev_ncalls;
short *ev_pncalls;
} ev_signal;
} ev_;
// 5. 标志位
short ev_events; // 用户关注的事件 (EV_READ, EV_WRITE, etc.)
short ev_res; // 当前激活的原因 (EV_READ, EV_TIMEOUT)
short ev_flags; // 内部状态 (EVLIST_INSERTED, EVLIST_ACTIVE)
unsigned char ev_pri; // 优先级
unsigned char ev_closure; // 闭包类型 (EV_CLOSURE_EVENT_SIGNAL, etc.)
// 6. 超时时间
struct timeval ev_timeout;
};注: 为了节省内存,Libevent 使用了大量的
union。一个事件不可能同时是 I/O 事件又是信号事件(虽然可以复用结构体,但逻辑上是互斥的)。
2. 核心字段解析
2.1. ev_events
(用户关注)
这是我们在 event_new 时传入的标志: *
EV_READ / EV_WRITE: 关注读/写。 *
EV_PERSIST:
持久化事件。默认情况下,事件触发一次回调后会自动从 Reactor
中移除(Non-persistent)。加上此标志后,事件会一直保持
Pending 状态,直到手动 event_del。 *
EV_ET: 边缘触发 (Edge Trigger)。
2.2. ev_flags
(内部状态)
这是 Libevent 内部维护事件生命周期的关键: *
EVLIST_INIT: 事件已初始化
(event_assign / event_new)。 *
EVLIST_INSERTED: 事件已注册到 Reactor
(event_add),处于 Pending
状态。 * EVLIST_ACTIVE:
事件已触发,正在等待处理或正在处理,处于
Active 状态。 *
EVLIST_TIMEOUT: 事件已注册到定时器堆中。 *
EVLIST_SIGNAL: 事件已注册到信号队列中。
2.3. ev_callback
封装了用户定义的回调函数和参数:
struct event_callback {
TAILQ_ENTRY(event_callback) evcb_active_next;
short evcb_flags;
unsigned char evcb_pri; // 优先级
unsigned char evcb_closure;
// 真正的回调函数指针
union {
void (*evcb_callback)(evutil_socket_t, short, void *);
void (*evcb_selfcb)(struct event_callback *, void *);
void (*evcb_cbfinalize)(struct event_callback *, void *);
} evcb_cb_union;
void *evcb_arg; // 用户参数
};3. 事件生命周期 (Lifecycle)
一个事件的一生通常经历以下阶段:
stateDiagram-v2
[*] --> Initialized: event_new()
Initialized --> Pending: event_add()
Pending --> Active: Triggered (IO/Timeout)
Active --> Pending: Callback done (if EV_PERSIST)
Active --> Initialized: Callback done (if !EV_PERSIST)
Pending --> Initialized: event_del()
Initialized --> [*]: event_free()
- Initialized (已初始化): 内存已分配,基本信息已填入,但 Reactor 还不知道它的存在。
- Pending (未决/注册): 调用
event_add后,事件被加入到event_base的关注列表(如 epoll 或最小堆)。此时它在等待事件发生。 - Active (激活):
- 硬件中断/系统调用返回,告知事件发生。
- Libevent 将其从 Pending 列表(如果是 IO 事件且非 PERSIST)移出。
- 将其加入到
activequeues中。
- Running (运行):
event_base_loop处理激活队列,调用用户回调。
4. 优先级 (Priority)
Libevent 支持事件优先级。默认情况下,所有事件优先级相同。
通过 event_priority_set(ev, priority)
可以设置。 * event_base 维护了一个
activequeues 数组,索引越小优先级越高。 *
高优先级的事件会被优先处理。 * 注意:
如果高优先级事件源源不断地产生,低优先级事件可能永远得不到执行(饥饿问题)。
5. 总结
struct event
是连接用户逻辑与底层内核的桥梁。它精细地管理着状态流转,确保每一个
I/O、每一个定时器都能被准确、高效地调度。
理解了 ev_flags 的状态变化,你在调试
Libevent 程序时(特别是面对 Core
Dump)就能一眼看出这个事件当前处于什么状态(是正在等数据,还是已经死掉了)。
上一篇: 01-core/cross-platform.md - 跨平台后端对比 下一篇: 02-data/evbuffer.md - Evbuffer 内存管理