3

请注意这是 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_XXXev_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 中指定的 signal
  • EV_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 watcher
  • EV_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_eventev_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 响应服务器的简单流程


amc
924 声望223 粉丝

电子和互联网深耕多年,拥有丰富的嵌入式和服务器开发经验。现负责腾讯心悦俱乐部后台开发