由于libevent支持 /dev/poll, kqueue(2), event ports, POSIX select(2), Windows select(), poll(2), and epoll(4).多平台网络IO,所以根据不同平台,也定义了不同eventop对象,它们被统一放入结构体指针数组eventops[]里。
libevent运用二进制形式,区分5种事件类型。event_add 函数用于添加超时、读、写、信号事件。超时事件由程序内部主动触发。老版本的超时事件的元素存在一个红黑树中,新版本引入了最小堆和队列共同来进行管理。下面介绍的都是libevent2.0.21版本内容。
先来介绍下对超时的管理,libevent用小根堆存储所有的超时时间,但是小根堆的时间复杂度为log(N),为了进一步提高效率,libevent采用了queue对相同超时间隔的Timer事件进行组织。Timer触发时间=当前绝对时间+超时间隔。所以具有相同超时间隔的Timer事件,它们的触发时间是不同的,可以按照升序排列在一起。
event_base_init_common_timeout函数用于初始化通用时间队列。
const struct timeval *
event_base_init_common_timeout(struct event_base *base,
const struct timeval *duration)
{
int i;
struct timeval tv;
const struct timeval *result=NULL;
struct common_timeout_list *new_ctl;
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
//有MICROSECONDS_MASK位的时间需要去除MICROSECONDS_MASK位才是真实的超时间隔
if (duration->tv_usec > 1000000) {
memcpy(&tv, duration, sizeof(struct timeval));
if (is_common_timeout(duration, base))
tv.tv_usec &= MICROSECONDS_MASK;
tv.tv_sec += tv.tv_usec / 1000000;
tv.tv_usec %= 1000000;
duration = &tv;
}
//判断超时间隔tv是否已经存在于通用时间队列中
for (i = 0; i < base->n_common_timeouts; ++i) {
const struct common_timeout_list *ctl =
base->common_timeout_queues[i];
if (duration->tv_sec == ctl->duration.tv_sec &&
durati