上一章分析了一下libevent中I/O多路复用的封装和实现,正如在select_dispatch中看到的,该函数由event_base_loo函数调用,且并不负责驱动具体事件。libevent中驱动事件的核心函数正是event_base_loop函数,该函数定义在event.c文件中。
不过在分析event_base_loop之前,首先再详细分析一下event_base这个核心数据结构
int event_base_loop(struct event_base *base, int flags) { const struct eventop *evsel = base->evsel; struct timeval tv; struct timeval *tv_p; int res, done, retval = 0; /* Grab the lock. We will release it inside evsel.dispatch, and again * as we invoke user callbacks. */ EVBASE_ACQUIRE_LOCK(base, th_base_lock); if (base->running_loop) { event_warnx("%s: reentrant invocation. Only one event_base_loop" " can run on each event_base at once.", __func__); EVBASE_RELEASE_LOCK(base, th_base_lock); return -1; } base->running_loop = 1; // 清除base->tv_cache.tv_sec, 否则下面timeout_correct函数不会重新取系统时间 clear_time_cache(base); // 注册了信号事件,并且监视到有信号事件发生 if (base->sig.ev_signal_added && base->sig.ev_n_signals_added) evsig_set_base(base); done = 0; #ifndef _EVENT_DISABLE_THREAD_SUPPORT base->th_owner_id = EVTHREAD_GET_ID(); #endif base->event_gotterm = base->event_break = 0; while (!done) { /* Terminate the loop if we have been asked to */ if (base->event_gotterm) { break; } if (base->event_break) { break; } // 更新时间,调整event_base中的时间堆timeheap timeout_correct(base, &tv); // 计算下面I/O多路复用的等待超时时间 // 如果有激活事件,则计算到timeheap中最近的时间间隔; 否则不等待 tv_p = &tv; if (!N_ACTIVE_CALLBACKS(base) && !(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) && !N_ACTIVE_CALLBACKS(base)) { event_debug(("%s: no events registered.", __func__)); retval = 1; goto done; } /* update last old time */ gettime(base, &base->event_tv); clear_time_cache(base); // 调用底层I/O多路复用机制封装,如select_dispatch res = evsel->dispatch(base, tv_p); if (res == -1) { event_debug(("%s: dispatch returned unsuccessfully.", __func__)); retval = -1; goto done; } update_time_cache(base); timeout_process(base); // 处理Active事件 if (N_ACTIVE_CALLBACKS(base)) { int n = event_process_active(base); if ((flags & EVLOOP_ONCE) && N_ACTIVE_CALLBACKS(base) == 0 && n != 0) done = 1; } else if (flags & EVLOOP_NONBLOCK) done = 1; } event_debug(("%s: asked to terminate loop.", __func__)); done: clear_time_cache(base); base->running_loop = 0; EVBASE_RELEASE_LOCK(base, th_base_lock); return (retval); }