libevent源码浅析(一)
副标题#e#
这里阐明的是libevent-1.4.9。
PS:前面还看了libev的源代码,妈的,那代码写的太猥亵了,对较量libevent代码写的许多几何了。。
首先来看一下最主要的几个数据布局:
eventop布局体是所有事件驱动模子的基类。所有的io复用范例城市实现此布局体里各类要领。
struct eventop {
const char *name; ///<事件驱动名称
void *(*init)(struct event_base *); //<初始化
int (*add)(void *, struct event *); ///<插手新的事件监测
int (*del)(void *, struct event *); ///<从事件监测中删除某一事件
int (*dispatch)(struct event_base *, void *, struct timeval *);///<启动此事件监测
void (*dealloc)(struct event_base *, void *); ///<释放此事件驱动的资源
/* set if we need to reinitialize the event base */
int need_reinit; ///<符号位
};
event_base打点所有的event工具,它包括了一些全部变量,好比事件驱动引擎evsel等。所有的event工具城市包括这个布局体。
struct event_base {
const struct eventop *evsel; ///<事件驱动引擎
void *evbase; ///<事件驱动引擎的全局数据,在每一个事件引擎文件中界说,下面会先容.
int event_count; /* counts number of total events */
int event_count_active; /* counts number of active events */
int event_gotterm; /* Set to terminate loop */
int event_break; /* Set to terminate loop immediately */
/* active event management */
struct event_list **activequeues; ///<激活行列
int nactivequeues; ///<激活行列数目
/* signal handling info */
struct evsignal_info sig; ///<信号
struct event_list eventqueue; ///<全部事件行列
struct timeval event_tv;
struct min_heap timeheap; ///<这里libevent将按时器行列实现为一个最小堆,也就是为了每次都把时间最晚的按时器能取出来,然后实现超时。更其实算法很简朴,想要具体的相识可以去看下算法导论的第六章的Priority queues.
struct timeval tv_cache;
};
event布局暗示每个事件,包括了一些事件私有的数据,好比回调函数等。。这里事件链表它利用了tail queue.
struct event {
TAILQ_ENTRY (event) ev_next; ///<下一个事件
TAILQ_ENTRY (event) ev_active_next; ///<下一个激活事件
TAILQ_ENTRY (event) ev_signal_next; ///<下一个信号事件列表
unsigned int min_heap_idx; /* for managing timeouts */
struct event_base *ev_base; ///<全局的base
int ev_fd; ///<所需要监测的事件句柄
short ev_events;
short ev_ncalls;
short *ev_pncalls; /* Allows deletes in callback */
struct timeval ev_timeout; ///<超时时间
int ev_pri; /* smaller numbers are higher priority */
void (*ev_callback)(int, short, void *arg); ///<回调函数
void *ev_arg; ///<通报给回调函数的参数
int ev_res; /* result passed to event callback */
int ev_flags;
};
#p#副标题#e#
下面来先容一下事件引擎中的两个布局,这里主要先容下select,其他的几本雷同.
selectop是全局的select数据布局,也就是上面event_base数据布局中evbase的值,我们通过avbase就可以操纵select的数据布局
struct selectop {
int event_fds; /* Highest fd in fd set */
int event_fdsz;
fd_set *event_readset_in;
fd_set *event_writeset_in;
fd_set *event_readset_out;
fd_set *event_writeset_out;
struct event **event_r_by_fd;
struct event **event_w_by_fd;
};
selectops也就是实现了eventop。它导出了select的接口。
const struct eventop selectops = {
"select",
select_init,
select_add,
select_del,
select_dispatch,
select_dealloc,
0
};
我们再来看下几个重要的函数(个中省略了一些语句,只先容重要的一些语句):
struct event_base *
event_base_new(void)
{
......................................
//前面就是一些初始化,最重要的部门是下面的这个for轮回。在这里初始化事件驱动引擎。这里eventops是一个eventop数组,内里包括所有事件驱动引擎的接口(就像上面先容的selectops布局)
for (i = 0; eventops[i] && !base->evbase; i++) {
base->evsel = eventops[i];
///下面挪用初始化函数,返回每个事件引擎的全局数据布局
base->evbase = base->evsel->init(base);
}
..................................
/* allocate a single active event queue */
event_base_priority_init(base, 1);
return (base);
}
event_init将event_base_new返回的值付给一个全局的变量current_base
Java代码
#p#分页标题#e#
struct event_base *
event_init(void)
{
struct event_base *base = event_base_new();
if (base != NULL)
current_base = base;
return (base);
}
event_add加一新的事件到当前事件引擎
int
event_add(struct event *ev, const struct timeval *tv)
{
///取恰当前事件的一些有用的数据布局。
struct event_base *base = ev->ev_base;
const struct eventop *evsel = base->evsel;
void *evbase = base->evbase;
int res = 0;
/*
* 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 (-1); /* ENOMEM == errno */
}
///这里挪用evsel->add来加一事件到当前的事件引擎。
if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
res = evsel->add(evbase, ev);
if (res != -1)
event_queue_insert(base, ev, EVLIST_INSERTED);
}
/*
* we should change the timout state only if the previous event
* addition succeeded.
*/
if (res != -1 && tv != NULL) {
struct timeval now;
/*
* we already reserved memory above for the case where we
* are not replacing an exisiting timeout.
*/
//假如超时就先删除此事件。
if (ev->ev_flags & EVLIST_TIMEOUT)
event_queue_remove(base, ev, EVLIST_TIMEOUT);
/* Check if it is active due to a timeout. Rescheduling
* this timeout before the callback can be executed
* removes it from the active list. */
if ((ev->ev_flags & EVLIST_ACTIVE) &&
(ev->ev_res & EV_TIMEOUT)) {
/* See if we are just active executing this
* event in a loop
*/
if (ev->ev_ncalls && ev->ev_pncalls) {
/* Abort loop */
*ev->ev_pncalls = 0;
}
event_queue_remove(base, ev, EVLIST_ACTIVE);
}
gettime(base, &now);
//计较超时时间并赋值给ev_timeout
evutil_timeradd(&now, tv, &ev->ev_timeout);
event_debug((
"event_add: timeout in %ld seconds, call %p",
tv->tv_sec, ev->ev_callback));
//将此按时器插手按时器最小堆。
event_queue_insert(base, ev, EVLIST_TIMEOUT);
}
return (res);
}
loop函数将进入事件监测轮回。
int
event_base_loop(struct event_base *base, int flags)
{
............................................
.......................................
///校准时间,非Monotonic时钟这个函数将会当即返回。
timeout_correct(base, &tv);
tv_p = &tv;
if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {
timeout_next(base, &tv_p);
} else {
/*
* if we have active events, we just poll new events
* without waiting.
*/
evutil_timerclear(&tv);
}
/* If we have no events, we just exit */
if (!event_haveevents(base)) {
event_debug(("%s: no events registered.", __func__));
return (1);
}
/* update last old time */
gettime(base, &base->event_tv);
/* clear time cache */
base->tv_cache.tv_sec = 0;
///挪用相应的事件引擎处理惩罚函数
res = evsel->dispatch(base, evbase, tv_p);
if (res == -1)
return (-1);
gettime(base, &base->tv_cache);
///超时处理惩罚函数(下面紧接着会先容)
timeout_process(base);
if (base->event_count_active) {
event_process_active(base);
if (!base->event_count_active && (flags & EVLOOP_ONCE))
done = 1;
} else if (flags & EVLOOP_NONBLOCK)
done = 1;
}
..................................................
}
超时处理惩罚函数
#p#分页标题#e#
void
timeout_process(struct event_base *base)
{
struct timeval now;
struct event *ev;
if (min_heap_empty(&base->timeheap))
return;
gettime(base, &now);
///遍历按时器
while ((ev = min_heap_top(&base->timeheap))) {
if (evutil_timercmp(&ev->ev_timeout, &now, >))
break;
/* delete this event from the I/O queues */
event_del(ev);
event_debug(("timeout_process: call %p",
ev->ev_callback));
///激活此事件
event_active(ev, EV_TIMEOUT, 1);
}
}