[libevent]事件主循环

libevent事件处理的中心部分——事件主循环,根据系统提供的事件多路分发机制执行事件循环,对已注册的就绪事件,调用注册事件的回调函数来处理事件。

事件处理主循环

上图的简单描述就是:

int event_base_loop(struct event_base *base, int flags){const struct eventop *evsel = base->evsel;void *evbase = base->evbase;struct timeval tv;struct timeval *tv_p;int res, done;// 清空时间缓存base->tv_cache.tv_sec = 0;// evsignal_base是全局变量,在处理signal时,用于指名signal所属的event_base实例if (base->sig.ev_signal_added)evsignal_base = base;done = 0;while (!done) { // 事件主循环// 查看是否需要跳出循环,程序可以调用event_loopexit_cb()设置event_gotterm标记// 调用event_base_loopbreak()设置event_break标记if (base->event_gotterm) {base->event_gotterm = 0;break;}if (base->event_break) {base->event_break = 0;break;}// 校正系统时间,如果系统使用的是非MONOTONIC时间,用户可能会向后调整了系统时间// 在timeout_correct函数里,比较last wait time和当前时间,如果当前时间< last wait time// 表明时间有问题,这是需要更新timer_heap中所有定时事件的超时时间。timeout_correct(base, &tv);// 根据timer heap中事件的最小超时时间,计算系统I/O demultiplexer的最大等待时间tv_p = &tv;if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {timeout_next(base, &tv_p);} else {// 依然有未处理的就绪时间,就让I/O demultiplexer立即返回,不必等待// 下面会提到,在libevent中,低优先级的就绪事件可能不能立即被处理evutil_timerclear(&tv);}// 如果当前没有注册事件,就退出if (!event_haveevents(base)) {event_debug(("%s: no events registered.", __func__));return (1);}// 更新last wait time,并清空time cachegettime(base, &base->event_tv);base->tv_cache.tv_sec = 0;// 调用系统I/O demultiplexer等待就绪I/O events,可能是epoll_wait,或者select等;// 在evsel->dispatch()中,会把就绪signal event、I/O event插入到激活链表中res = evsel->dispatch(base, evbase, tv_p);if (res == -1)return (-1);// 将time cache赋值为当前系统时间gettime(base, &base->tv_cache);// 检查heap中的timer events,将就绪的timer event从heap上删除,并插入到激活链表中timeout_process(base);// 调用event_process_active()处理激活链表中的就绪event,调用其回调函数执行事件处理// 该函数会寻找最高优先级(priority值越小优先级越高)的激活事件链表,// 然后处理链表中的所有就绪事件;// 因此低优先级的就绪事件可能得不到及时处理;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;}// 循环结束,清空时间缓存base->tv_cache.tv_sec = 0;event_debug(("%s: asked to terminate loop.", __func__));return (0);}

I/O

.堆是一种经典的数据结构,,向堆中插入、删除元素时间复杂度都是

I/O

//libevent中Signal事件的管理是通过结构体evsignal_info完成的,结构体位于evsignal.h文件中,定义如下:struct evsignal_info { struct event ev_signal; //为socket pair的读socket向event_base注册读事件时使用的event结构体int ev_signal_pair[2]; //socket pair对int ev_signal_added; //记录ev_signal事件是否已经注册了volatile sig_atomic_t evsignal_caught; //是否有信号发生的标记;是volatile类型,因为它会在另外的线程中被修改;struct event_list evsigevents[NSIG]; //数组,evsigevents[signo]表示注册到信号signo的事件链表;sig_atomic_t evsigcaught[NSIG]; //具体记录每个信号触发的次数,evsigcaught[signo]是记录信号signo被触发的次数;#ifdef HAVE_SIGACTION struct sigaction **sh_old; #else ev_sighandler_t **sh_old; //记录了原来的signal处理函数指针,当信号signo注册的event被清空时,需要重新设置其处理函数;#endif int sh_old_max; }; //的初始化包括,创建socket pair,设置ev_signal事件(但并没有注册,而是等到有信号注册时才检查并注册),并将所有标记置零,初始化信号的注册事件链表指针等。

运行循环

#define EVLOOP_ONCE0x01#define EVLOOP_NONBLOCK0x02#define EVLOOP_NO_EXIT_ON_EMPTY 0x04int event_base_loop(struct event_base *base, int flags);

()的行为。

为方便起见,也可以调用int event_base_dispatch(struct event_base *base);

event_base_dispatch()等同于没有设置标志的event_base_loop()。所以,event_base_dispatch()将一直运行,直到没有已经注册的事件了,或者调用了event_base_loopbreak()或者event_base_loopexit()为止。

停止循环

如果想在移除所有已注册的事件之前停止活动的事件循环,可以调用两个稍有不同的函数。

int event_base_loopexit(struct event_base *base,const struct timeval *tv);int event_base_loopbreak(struct event_base *base);

int event_base_got_exit(struct event_base *base);int event_base_got_break(struct event_base *base);

勇士面前无险路。

[libevent]事件主循环

相关文章:

你感兴趣的文章:

标签云: