[c]
#include
#include
ev_io stdin_watcher;
ev_timer timeout_watcher;
static void stdin_cb(EV_P_ ev_io *w, int revents) {
puts("stdin ready");
ev_io_stop(EV_A_ w);
ev_break(EV_A_ EVBREAK_ALL);
}
static void timeout_cb(EV_P_ ev_timer *w, int revents) {
puts("timeout");
ev_break(EV_A_ EVBREAK_ONE);
}
int main() {
struct ev_loop *loop = EV_DEFAULT;
ev_io_init(&stdin_watcher, stdin_cb, 0, EV_READ);
ev_io_start(loop, &stdin_watcher);
ev_timer_init(&timeout_watcher, timeout_cb, 5.5, 0.);
ev_timer_start(loop, &timeout_watcher);
ev_run(loop, 0);
return 0;
}
[c]
// ev.h 關鍵宏 (簡化)
#define ev_io_init(ev, cb, fd, events) \
do { ev_init((ev), (cb)); ev_io_set((ev), (fd), (events)); } while(0)
#define ev_init(ev, cb_) \
do { \
((ev_watcher*)(ev))->active = 0; \
((ev_watcher*)(ev))->pending = 0; \
ev_set_priority((ev), 0); \
ev_set_cb((ev), cb_); \
} while(0)
#define ev_io_set(ev, fd_, events_) \
do { (ev)->fd = (fd_); (ev)->events = (events_) | EV__IOFDSET; } while(0)
ev_io_init 完成:active=0, pending=0, priority=0, cb=stdin_cb, fd=0, events=EV_READ|EV__IOFDSET。
ev_io_start 註冊流程active 防重複註冊。fdchanges 陣列 (標記該 fd 有變更)。backend_modify (epoll_ctl EPOLL_CTL_ADD/MOD) 向內核註冊事件。active = 1。ev_run 事件循環核心[c]
// 簡化邏輯
void ev_run(struct ev_loop *loop, int flags) {
while (1) {
// 1. 收集 fdchanges,批次調用 backend_modify 同步內核
// 2. 計算最近 timer 到期時間 → timeout
// 3. backend_poll(timeout) → epoll_wait/poll/select/kqueue
// 4. 遍歷就緒事件,設定 watcher->pending, revents
// 5. 調用 watcher->cb(loop, watcher, revents)
// 6. 處理 pending timer / idle / prepare / check / async
// 7. 若 flags == EVRUN_ONCE 或無 active watcher 或 ev_break 被調用 → 退出
}
}
libev 透過 struct ev_method 統一不同 OS 的 I/O 多路複用介面:
[c]
static struct ev_method {
const char *name;
void (*init)(EV_P);
void (*destroy)(EV_P);
void (*modify)(EV_P_ int fd, int oev, int nev);
void (*poll)(EV_P_ ev_tstamp timeout);
} *backend;
Linux 下 backend = &epoll_method:
init:epoll_create1(EPOLL_CLOEXEC) 建立 epfd。modify:epoll_ctl(epfd, op, fd, &ev),op 為 ADD/MOD/DEL。poll:epoll_wait(epfd, events, maxevents, timeout_ms),將就緒事件轉為 libev 內部 revents 並喚醒對應 watcher。
main()
└─ ev_run(loop, 0)
├─ backend_modify() [同步 fdchanges 到 epoll]
├─ backend_poll() [epoll_wait()]
│ └─ 內核返回就緒 fd 列表
├─ 遍歷就緒事件
│ ├─ 找到對應 watcher
│ ├─ watcher->pending = 1; watcher->revents = EV_READ/WRITE
│ └─ watcher->cb(loop, watcher, revents) ← 用戶回調 (stdin_cb)
├─ 處理 timer (timeout_watcher)
│ └─ timeout_cb()
└─ 檢查 break 條件 → 循環或退出

O(log n) 插入/刪除,O(1) 取最小,無需輪詢。fdchanges 合併同一循環內多次 ev_io_start/stop,單次 epoll_ctl 系統調用。