本节我们依旧来分析event
的操作, 接着上节没有讲完的关于event的注册和注销两个功能的实现.
event 注册
依旧来看一个event 注册函数的原型
int event_add(struct event *ev, const struct timeval *tv);
相比event_set
函数event_add
真的很干净.
参数
- ev : 将要注册的event事件. 其实实际注册的是
ev->ev_base
. - tv : 设置超时时间. 如果
tv != NULL
则会同时注册定时事件, 将ev
添加到timer堆上.
函数源码event.c
函数真的很长, 不慌, 我们慢慢的分析(基本在注释中).
// 设置事件的定时. 实质 : 注册事件
// 1. 如果设置定时, 则先在小根堆上申请一个注册的空间
// 2. 如果事件已经处于定时队列, 则将其从定时队列中移除
// 3. 如果事件已经在就绪队列中, 则将其从就绪队列中移除
// 4. 重新设置定时时间, 并将其插入到定时队列中
int
event_add(struct event *ev, const struct timeval *tv)
{
struct event_base *base = ev->ev_base; // 指向要注册的 ev_base
const struct eventop *evsel = base->evsel;
void *evbase = base->evbase; // base 所使用的IO成员
int res = 0;
event_debug((
"event_add: event: %p, %s%s%scall %p",
ev,
ev->ev_events & EV_READ ? "EV_READ " : " ",
ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
tv ? "EV_TIMEOUT " : " ",
ev->ev_callback));
assert(!(ev->ev_flags & ~EVLIST_ALL));
/*
* prepare for timeout insertion further below, if we get a
* failure on any step, we should not change any state.
*/
// 如果设置了定时, 则现在先在小根堆上分配一个空位留给定时事件, 保证注册定时事件时不会失败
if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
if (min_heap_reserve(&base->timeheap,
1 + min_heap_size(&base->timeheap)) == -1)
return (-