请注意这是 libev 而不是 libevent 的文章!
这篇文章是第二篇,主要讲 libev 里的 watcher 的一些基础操作。
本文地址:https://segmentfault.com/a/1190000006200077
Watcher 解析
以下是一段示意性的代码,使用的是ev_io
:
static void my_cb (struct ev_loop *loop, ev_io *w, int revents)
{
ev_io_stop (w);
ev_break (loop, EVBREAK_ALL);
}
some_main()
{
...
struct ev_loop *loop = ev_default_loop (0);
ev_io stdin_watcher;
ev_init (&stdin_watcher, my_cb);
ev_io_set (&stdin_watcher, STDIN_FILENO, EV_READ);
ev_io_start (loop, &stdin_watcher);
ev_run (loop, 0);
...
}
每一个 watcher 类型有一个附属的 watcher 结构体。(一般是struct ev_XXX
或ev_XXX
)
每一个 watcher 结构都需要用ev_init
初始化,每一个 watcher 都有对应的ev_XXX_set
函数、ev_XXX_start
函数、ev_XXX_stop
函数。在 ev_run 之前进行各个 watcher 的 ev_start。
只要 watcher 是 active,就不能再调用 init。
每个 callback 都有三个参数:loop, watcher, 事件的掩码值。可能的掩码值有:
EV_READ
EV_WRITE
EV_TIMER
:ev_timer 超时EV_PERIODIC
:ev_periodic 超时EV_SIGNAL
:某线程接收了 ev_signal 中指定的 signalEV_CHILD
:ev_child 中指定的 pid 获得了一个状态变化EV_STAT
:ev_stat 中指定的 path 的属性修改了EV_IDLE
:ev_idle watcher 发现无事可做EV_PREPARE
,EV_CHECK
:所有 ev_prepare watchers 在 loop 开始收集事件前调用;所有ev_check watchers 则在以后调用。回调可在这两个 watchers 中开始/停止相应的 watchers。EV_EMBED
:ev_embed watcherEV_CLEANUP
:event loop 即将被销毁EV_ASYNC
:asuny watcher 已经被异步通知EV_CUSTOM
:不是 libev 发送的信号。参见ev_feed_event
EV_ERROR
:在 libev 内存不够用时可能产生;fd 被外部关闭时也可能产生
通用 watcher 函数
void ev_init (ev_TYPE *watcher, callback)
使用这个宏初始化 watcher。此外还需要调用相应的 ev_XXX_set
函数。参见下文:
void ev_TYPE_set (ev_TYPE *watcher, [args])
设置指定类型的 wetaher。init 函数必须在此之前被调用一次,此后可以设置任意次的 set 函数。
不能对一个 active 的 watcher 调用此函数,但 pending 可以。比如:ev_io w;
ev_init (&w, my_cb);
ev_io_set (&w, STDIN_FILENO, EV_READ);
void ev_TYPE_set (ev_TYPE *watcher, callback, [args])
这个宏将 init 和 set 糅合在一起使用
void ev_TYPE_start (loop, ev_TYPE *watcher)
开始(激活)指定的 watcher。如果 watcher 已经是 active,则调用无效。
void ev_TYPE_stop (loop, ev_TYPE *watcher)
停止 watcher,并清空 pending 状态。如果要释放一个 Watcher,最好都显式地调用 stop。
bool ev_is_active (ev_TYPE *watcher)
如果 watcher 被执行了一次 start,并且未被 stop,则返回 true。
bool ev_is_pending (ev_TYPE *watcher)
当且仅当 watcher pending 时返回 true。(如:有未决的事件,但是 callback 未被调用)
callback ev_cb (ev_TYPE *watcher)
void ev_set_cb (ev_TYPE *watcher, callback)
读 / 写 callback
void ev_set_priority (ev_TYPE *watcher, int priority)
int ev_priority (ev_TYPE *watcher)
Priority 是一个介于EV_MAXPRI
(默认2)和EV_MIN_PRI
(默认-2)之间的值。数值越高越优先被调用。但除了 ev_idle,每一个 watcher 都会被调用。
当 watcher 是 active 或 pending 时并不能修改。
实际上 priority 大于-2到2的范围也是没问题的。
void ev_invoke (loop, ev_TYPE *watcher, int revents);
使用指定的参数调用 callback
int ev_clear_pending (loop, ev_TYPE *watcher);
清除指定 watcher 的 pending 状态,并且返回 revents 位。如果 watcher 不是 pending 则返回0
void ev_feed_event (loop, ev_TYPE *watcher, int revents)
模拟一个事件。参见ev_feed_fd_event
和ev_feed_signal_event
Watcher 状态
除了前文提及的 active 和 pending 状态之外,本小节描述了更加详细的 watcher 状态。
initialized
:通过调用ev_TYPE_init
对 watcher 进行初始化,这是注册到 loop 之前的必要步骤。可以再次调用 ev_TYPE_init 进行操作。
started
/running
/active
:调用ev_TYPE_start
之后的状态,并且开始等待事件。在这个状态下,除了特别提及的少数情况之外,它不能存取、移动、释放,只能维持着对它的指针。
pending
:当 watcher 是 active 并且一个让 watcher 感兴趣的事件到来,那么 watcher 进入 pending。这个状态的 watcher 可以 access,但不能存取、移动、释放。
stopped
:调用ev_TYPE_stop
,此时状态与 initialized 相同。
系列篇
Libev 官方文档学习笔记(1)——概述和 ev_loop
Libev 官方文档学习笔记(2)——watcher 基础(本文)
Libev 官方文档学习笔记(3)——常用 watcher 接口
使用 libev 构建 TCP 响应服务器的简单流程