一、event_base_loop
此函數主要運行激活事件;它會根據配置中的參數來確定是否需要在執行激活事件過程中中斷執行並檢查新事件以及檢查頻率;
同時也會根據事件類型執行不同的回調函數,並且決定是否將事件重新添加到隊列中;
/**
Wait for events to become active, and run their callbacks.
This is a more flexible version of event_base_dispatch().
By default, this loop will run the event base until either there are no more
pending or active events, or until something calls event_base_loopbreak() or
event_base_loopexit(). You can override this behavior with the 'flags'
argument.
@param eb the event_base structure returned by event_base_new() or
event_base_new_with_config()
@param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
@return 0 if successful, -1 if an error occurred, or 1 if we exited because
no events were pending or active.
@see event_base_loopexit(), event_base_dispatch(), EVLOOP_ONCE,
EVLOOP_NONBLOCK
*/
// 等待事件變爲活躍,然後運行事件回調函數。
// 相比event_base_dispatch函數,這個函數更爲靈活。默認情況下,loop會一直運行到沒有等待事件或者激活的事件,或者
// 運行到調用event_base_loopbreak或者event_base_loopexit函數。你可以使用’flags‘調整loop行爲。
// 參數 eb:event_base_new或者event_base_new_with_config產生的event_base結構體
// flags:可以是EVLOOP_ONCE|EVLOOP_NONBLOCK
// 返回值:成功則爲0,失敗則爲-1,如果因爲沒有等待的事件或者激活事件而退出則返回1
// 相關查看event_base_loopexit,event_base_dispatch
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;
// 清空當前event_base中的時間,防止誤用
clear_time_cache(base);
// 如果event_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) {
base->event_continue = 0;
base->n_deferreds_queued = 0;
/* Terminate the loop if we have been asked to */
// 每次loop時,需要判定是否別的地方已經設置了終止或者退出的標誌位
if (base->event_gotterm) {
break;
}
if (base->event_break) {
break;
}
tv_p = &tv;
// 如果event_base的活躍事件數量爲空並且是非阻塞模式,則獲取下一個超時事件的距離超時的時間間隔,用於後臺
// 方法用於調度超時事件,否則清空存儲距離超時的時間間隔。
// 下文分析
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 */
// 如果沒有事件並且模式是EVLOOP_NO_EXIT_ON_EMPTY,則退出
if (0==(flags&EVLOOP_NO_EXIT_ON_EMPTY) &&
!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
event_debug(("%s: no events registered.", __func__));
retval = 1;
goto done;
}
// 將later 事件激活放入活躍隊列
event_queue_make_later_events_active(base);
// 清空event_base中時間,防止誤用
clear_time_cache(base);
// 調用後臺方法的dispatch方法
res = evsel->dispatch(base, tv_p);
if (res == -1) {
event_debug(("%s: dispatch returned unsuccessfully.",
__func__));
retval = -1;
goto done;
}
// 更新當前event_base中緩存的時間,因爲這是在執行後臺調度方法之後的時間,可以用來作爲超時事件的參考時間
update_time_cache(base);
// 主要是從超時事件最小堆中取出超時事件,並將超時事件放入激活隊列
timeout_process(base);
// 如果激活隊列不爲空,則處理激活的事件
// 否則,如果模式爲非阻塞,則退出loop
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);
}
二、timeout_next
主要是獲取下一個超時事件超過超時時間的時間間隔;如果沒有超時事件,則存儲超時間隔則爲空static int
timeout_next(struct event_base *base, struct timeval **tv_p)
{
/* Caller must hold th_base_lock */
struct timeval now;
struct event *ev;
struct timeval *tv = *tv_p;
int res = 0;
// 獲取最小堆根部事件,如果爲空,則返回
ev = min_heap_top_(&base->timeheap);
if (ev == NULL) {
/* if no time-based events are active wait for I/O */
*tv_p = NULL;
goto out;
}
// 獲取base中現在的時間,如果base中時間爲空,則獲取現在系統中的時間
if (gettime(base, &now) == -1) {
res = -1;
goto out;
}
// 比較事件超時時間和當前base中的時間,如果超時時間<=當前時間,則表明已經超時,則返回即可;
// 如果超時時間>當前時間,表明超時時間還沒到,將超時時間-當前時間的結果存儲在tv中,即超過超時時間的時間間隔
if (evutil_timercmp(&ev->ev_timeout, &now, <=)) {
evutil_timerclear(tv);
goto out;
}
evutil_timersub(&ev->ev_timeout, &now, tv);
EVUTIL_ASSERT(tv->tv_sec >= 0);
EVUTIL_ASSERT(tv->tv_usec >= 0);
event_debug(("timeout_next: event: %p, in %d seconds, %d useconds", ev, (int)tv->tv_sec, (int)tv->tv_usec));
out:
return (res);
}
三、event_queue_make_later_events_active函數
主要是將下一次激活事件隊列中的事件都移動到激活隊列中static void
event_queue_make_later_events_active(struct event_base *base)
{
struct event_callback *evcb;
EVENT_BASE_ASSERT_LOCKED(base);
// 判斷下一次激活隊列中是否還存在回調事件,如果存在,則將回調事件狀態增加激活狀態,
// 然後將該回調事件插入對應優先級的激活隊列中,並將推遲的事件總數+1
while ((evcb = TAILQ_FIRST(&base->active_later_queue))) {
TAILQ_REMOVE(&base->active_later_queue, evcb, evcb_active_next);
evcb->evcb_flags = (evcb->evcb_flags & ~EVLIST_ACTIVE_LATER) | EVLIST_ACTIVE;
EVUTIL_ASSERT(evcb->evcb_pri < base->nactivequeues);
TAILQ_INSERT_TAIL(&base->activequeues[evcb->evcb_pri], evcb, evcb_active_next);
base->n_deferreds_queued += (evcb->evcb_closure == EV_CLOSURE_CB_SELF);
}
}
四、後臺方法的調度方法,以epoll爲例
static int
epoll_dispatch(struct event_base *base, struct timeval *tv)
{
struct epollop *epollop = base->evbase;
struct epoll_event *events = epollop->events;
int i, res;
long timeout = -1;
#ifdef USING_TIMERFD
if (epollop->timerfd >= 0) {
struct itimerspec is;
is.it_interval.tv_sec = 0;
is.it_interval.tv_nsec = 0;
if (tv == NULL) {
/* No timeout; disarm the timer. */
is.it_value.tv_sec = 0;
is.it_value.tv_nsec = 0;
} else {
if (tv->tv_sec == 0 && tv->tv_usec == 0) {
/* we need to exit immediately; timerfd can't
* do that. */
timeout = 0;
}
is.it_value.tv_sec = tv->tv_sec;
is.it_value.tv_nsec = tv->tv_usec * 1000;
}
/* TODO: we could avoid unnecessary syscalls here by only
calling timerfd_settime when the top timeout changes, or
when we're called with a different timeval.
*/
if (timerfd_settime(epollop->timerfd, 0, &is, NULL) < 0) {
event_warn("timerfd_settime");
}
} else
#endif
// 如果存在超時事件,則將超時時間轉換爲毫秒時間
// 如果超時時間在合法範圍之外,則設置超時時間爲永久等待
if (tv != NULL) {
timeout = evutil_tv_to_msec_(tv);
if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) {
/* Linux kernels can wait forever if the timeout is
* too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */
timeout = MAX_EPOLL_TIMEOUT_MSEC;
}
}
// 將event_base中有改變的事件列表都根據事件類型應用到epoll的監聽上;重新設置之後,則刪除改變
epoll_apply_changes(base);
event_changelist_remove_all_(&base->changelist, base);
// 等待事件觸發,如果沒有超時事件時(tv=null)時,timeout=-1,則爲阻塞模式
EVBASE_RELEASE_LOCK(base, th_base_lock);
res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
if (res == -1) {
if (errno != EINTR) {
event_warn("epoll_wait");
return (-1);
}
return (0);
}
event_debug(("%s: epoll_wait reports %d", __func__, res));
EVUTIL_ASSERT(res <= epollop->nevents);
// 根據epoll等待觸發的事件列表激活事件
for (i = 0; i < res; i++) {
int what = events[i].events;
short ev = 0;
#ifdef USING_TIMERFD
if (events[i].data.fd == epollop->timerfd)
continue;
#endif
if (what & (EPOLLHUP|EPOLLERR)) {
ev = EV_READ | EV_WRITE;
} else {
if (what & EPOLLIN)
ev |= EV_READ;
if (what & EPOLLOUT)
ev |= EV_WRITE;
if (what & EPOLLRDHUP)
ev |= EV_CLOSED;
}
if (!ev)
continue;
// 根據事件綁定的fd,事件類型以及觸發方式激活事件
evmap_io_active_(base, events[i].data.fd, ev | EV_ET);
}
// 如果激活的事件個數等於epoll中事件總數,同時epoll中事件總數小於最大總數,
// 則需要創建新空間用來存儲新事件,方法是每次創建的空間等於原來的2倍
if (res == epollop->nevents && epollop->nevents < MAX_NEVENT) {
/* We used all of the event space this time. We should
be ready for more events next time. */
int new_nevents = epollop->nevents * 2;
struct epoll_event *new_events;
new_events = mm_realloc(epollop->events,
new_nevents * sizeof(struct epoll_event));
if (new_events) {
epollop->events = new_events;
epollop->nevents = new_nevents;
}
}
return (0);
}
五、evmap_io_active_:epoll_dispatch中調用
根據fd和事件類型之間的映射表,找出所有該類型事件,全部激活,將註冊到指定fd上的特定事件類型的事件插入激活隊列中
void
evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events)
{
struct event_io_map *io = &base->io;
struct evmap_io *ctx;
struct event *ev;
#ifndef EVMAP_USE_HT
if (fd < 0 || fd >= io->nentries)
return;
#endif
// 根據文件描述符獲取該fd上註冊的所有事件列表
GET_IO_SLOT(ctx, io, fd, evmap_io);
if (NULL == ctx)
return;
// 遍歷該描述符上註冊事件列表,找出事件類型與觸發事件類型一致的事件,並將事件
LIST_FOREACH(ev, &ctx->events, ev_io_next) {
if (ev->ev_events & events)
event_active_nolock_(ev, ev->ev_events & events, 1);
}
}
六、event_active_nolock_:evmap_io_active_中調用
激活指定類型的事件// ev:激活的事件
// res:激活的事件類型
// ncalls:該事件需要激活的次數,主要是應對信號事件,某些信號事件可能會註冊多次,所以需要激活多次
void
event_active_nolock_(struct event *ev, int res, short ncalls)
{
struct event_base *base;
event_debug(("event_active: %p (fd "EV_SOCK_FMT"), res %d, callback %p",
ev, EV_SOCK_ARG(ev->ev_fd), (int)res, ev->ev_callback));
base = ev->ev_base;
EVENT_BASE_ASSERT_LOCKED(base);
if (ev->ev_flags & EVLIST_FINALIZING) {
/* XXXX debug */
return;
}
// 根據激活的事件類型
switch ((ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
default:
case EVLIST_ACTIVE|EVLIST_ACTIVE_LATER:
EVUTIL_ASSERT(0);
break;
case EVLIST_ACTIVE:
/* We get different kinds of events, add them together */
ev->ev_res |= res;
return;
case EVLIST_ACTIVE_LATER:
ev->ev_res |= res;
break;
case 0:
ev->ev_res = res;
break;
}
if (ev->ev_pri < base->event_running_priority)
base->event_continue = 1;
// 如果是信號事件,則需要設置調用次數
if (ev->ev_events & EV_SIGNAL) {
#ifndef EVENT__DISABLE_THREAD_SUPPORT
if (base->current_event == event_to_event_callback(ev) &&
!EVBASE_IN_THREAD(base)) {
++base->current_event_waiters;
EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
}
#endif
ev->ev_ncalls = ncalls;
ev->ev_pncalls = NULL;
}
// 激活事件實際上就是將事件的回調函數放入激活隊列
event_callback_activate_nolock_(base, event_to_event_callback(ev));
}
七、event_callback_activate_nolock_:激活事件的回調函數,event_active_nolock_調用
int
event_callback_activate_nolock_(struct event_base *base,
struct event_callback *evcb)
{
int r = 1;
// 合法狀態檢查
if (evcb->evcb_flags & EVLIST_FINALIZING)
return 0;
switch (evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)) {
default:
EVUTIL_ASSERT(0);
EVUTIL_FALLTHROUGH;
case EVLIST_ACTIVE_LATER:
// 如果事件狀態爲EVLIST_ACTIVE_LATER,則將回調函數從下一次激活隊列中移除
event_queue_remove_active_later(base, evcb);
r = 0;
break;
case EVLIST_ACTIVE:
return 0;
case 0:
break;
}
// 將回調函數插入激活隊列
event_queue_insert_active(base, evcb);
// 通知主線程loop
if (EVBASE_NEED_NOTIFY(base))
evthread_notify_base(base);
return r;
}
八、event_queue_insert_active:插入激活隊列,event_callback_activate_nolock_調用
static void
event_queue_insert_active(struct event_base *base, struct event_callback *evcb)
{
EVENT_BASE_ASSERT_LOCKED(base);
if (evcb->evcb_flags & EVLIST_ACTIVE) {
/* Double insertion is possible for active events */
return;
}
// 增加base中事件數量,並設置回調函數的執行狀態爲激活狀態
INCR_EVENT_COUNT(base, evcb->evcb_flags);
evcb->evcb_flags |= EVLIST_ACTIVE;
// 激活事件數量增加,並將激活事件回調函數插入所在優先級隊列中
base->event_count_active++;
MAX_EVENT_COUNT(base->event_count_active_max, base->event_count_active);
EVUTIL_ASSERT(evcb->evcb_pri < base->nactivequeues);
TAILQ_INSERT_TAIL(&base->activequeues[evcb->evcb_pri],
evcb, evcb_active_next);
}
九、timeout_process:將超時事件放入激活隊列,event_base_loop調用
/* Activate every event whose timeout has elapsed. */
// 激活超時事件
static void
timeout_process(struct event_base *base)
{
/* Caller must hold lock. */
struct timeval now;
struct event *ev;
// 如果超時最小堆爲空,則沒有超時事件,直接返回即可
if (min_heap_empty_(&base->timeheap)) {
return;
}
// 獲取當前base中的時間,用於下面比較超時事件是否超時
gettime(base, &now);
// 遍歷最小堆,如果最小堆中超時事件沒有超時的,則退出循環;
// 如果有超時的事件,則先將超時事件移除,然後激活超時事件;
// 先將超時事件移除的原因是:事件已超時,所以需要激活,就不需要繼續監控了;
// 還有就是對於永久性監控的事件,可以在執行事件時重新加入到監控隊列中,同時可以重新配置超時時間
while ((ev = min_heap_top_(&base->timeheap))) {
// ev->ev_timeout > now,表明當前時間還沒有到事件超時時間,那麼最小堆中的其它事件肯定也沒有超時,可以退出循環
if (evutil_timercmp(&ev->ev_timeout, &now, >))
break;
/* delete this event from the I/O queues */
event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
event_debug(("timeout_process: event: %p, call %p",
ev, ev->ev_callback));
event_active_nolock_(ev, EV_TIMEOUT, 1);
}
}
十、event_process_active:處理激活事件,event_base_loop調用
/*
* Active events are stored in priority queues. Lower priorities are always
* process before higher priorities. Low priority events can starve high
* priority ones.
*/
// 激活存儲在優先級隊列中的事件;表示優先級的數字越小,優先級越高;
// 優先級高的事件可能會一直阻塞低優先級事件運行;
static int
event_process_active(struct event_base *base)
{
/* Caller must hold th_base_lock */
struct evcallback_list *activeq = NULL;
int i, c = 0;
const struct timeval *endtime;
struct timeval tv;
// 獲取重新檢查新事件產生之前,可以處理的回調函數的最大個數;
// 優先級低於limit_callbacks_after_prio的事件執行時,纔會檢查新事件,否則不檢查
const int maxcb = base->max_dispatch_callbacks;
const int limit_after_prio = base->limit_callbacks_after_prio;
// 如果檢查新事件間隔時間 >=0,爲了檢查間隔更爲精確,則需要更新base中的時間,並獲取base中當前的時間;
// 然後計算下一次檢查的時間=base->max_dispatch_time + tv
if (base->max_dispatch_time.tv_sec >= 0) {
update_time_cache(base);
gettime(base, &tv);
evutil_timeradd(&base->max_dispatch_time, &tv, &tv);
endtime = &tv;
} else {
endtime = NULL;
}
// 如果base中激活隊列不爲空,則根據優先級遍歷激活隊列;
// 遍歷每一個優先級子隊列,處理子隊列中回調函數;
// 在執行時,需要根據limit_after_prio設置兩次檢查新事件之間的間隔;
// 如果優先級 < limit_after_prio,即當事件優先級高於limit_after_prio時,是不需要查看新事件的;
// 如果優先級 >= limit_after_prio,即當事件優先級不高於limit_after_prio時,是需要根據maxcb以及end_time檢查新事件;
for (i = 0; i < base->nactivequeues; ++i) {
if (TAILQ_FIRST(&base->activequeues[i]) != NULL) {
base->event_running_priority = i;
activeq = &base->activequeues[i];
if (i < limit_after_prio)
c = event_process_active_single_queue(base, activeq,
INT_MAX, NULL);
else
c = event_process_active_single_queue(base, activeq,
maxcb, endtime);
if (c < 0) {
goto done;
} else if (c > 0)
break; /* Processed a real event; do not
* consider lower-priority events */
/* If we get here, all of the events we processed
* were internal. Continue. */
}
}
done:
base->event_running_priority = -1;
return c;
}
十一、event_process_active_single_queue
/*
Helper for event_process_active to process all the events in a single queue,
releasing the lock as we go. This function requires that the lock be held
when it's invoked. Returns -1 if we get a signal or an event_break that
means we should stop processing any active events now. Otherwise returns
the number of non-internal event_callbacks that we processed.
*/
// event_process_active函數的幫助實現函數;用於處理單個優先級隊列中的所有事件;
// 當執行完畢時,需要釋放鎖;這個函數要求加鎖;如果獲得一個信號或者event_break時,
// 意味着需要停止執行任何活躍事件,則返回-1;否則返回已經處理的非內部event_callbacks的個數;
// base:event_base句柄
// activeq:激活回調函數隊列
// max_to_process:檢查新事件之間執行的回調函數的最大個數
// endtime:
static int
event_process_active_single_queue(struct event_base *base,
struct evcallback_list *activeq,
int max_to_process, const struct timeval *endtime)
{
struct event_callback *evcb;
int count = 0;
EVUTIL_ASSERT(activeq != NULL);
// 遍歷子隊列,需要根據
for (evcb = TAILQ_FIRST(activeq); evcb; evcb = TAILQ_FIRST(activeq)) {
struct event *ev=NULL;
// 如果回調函數狀態爲初始化狀態
if (evcb->evcb_flags & EVLIST_INIT) {
ev = event_callback_to_event(evcb);
// 如果回調函數對應的事件爲永久事件,或者事件狀態爲結束,則將事件回調函數從激活隊列中移除;
// 否則,則需要刪除事件;
if (ev->ev_events & EV_PERSIST || ev->ev_flags & EVLIST_FINALIZING)
event_queue_remove_active(base, evcb);
else
event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
event_debug((
"event_process_active: event: %p, %s%s%scall %p",
ev,
ev->ev_res & EV_READ ? "EV_READ " : " ",
ev->ev_res & EV_WRITE ? "EV_WRITE " : " ",
ev->ev_res & EV_CLOSED ? "EV_CLOSED " : " ",
ev->ev_callback));
} else {
// 如果是其它狀態,則將回調函數從激活隊列中移除
event_queue_remove_active(base, evcb);
event_debug(("event_process_active: event_callback %p, "
"closure %d, call %p",
evcb, evcb->evcb_closure, evcb->evcb_cb_union.evcb_callback));
}
// 如果回調函數狀態爲非內部狀態,則執行的事件個數+1
if (!(evcb->evcb_flags & EVLIST_INTERNAL))
++count;
// 設置當前的事件
base->current_event = evcb;
#ifndef EVENT__DISABLE_THREAD_SUPPORT
base->current_event_waiters = 0;
#endif
// 根據事件回調函數模式,執行不同的回調函數
switch (evcb->evcb_closure) {
case EV_CLOSURE_EVENT_SIGNAL:
EVUTIL_ASSERT(ev != NULL);
event_signal_closure(base, ev);
break;
case EV_CLOSURE_EVENT_PERSIST:
EVUTIL_ASSERT(ev != NULL);
event_persist_closure(base, ev);
break;
case EV_CLOSURE_EVENT: {
void (*evcb_callback)(evutil_socket_t, short, void *);
EVUTIL_ASSERT(ev != NULL);
evcb_callback = *ev->ev_callback;
EVBASE_RELEASE_LOCK(base, th_base_lock);
evcb_callback(ev->ev_fd, ev->ev_res, ev->ev_arg);
}
break;
case EV_CLOSURE_CB_SELF: {
void (*evcb_selfcb)(struct event_callback *, void *) = evcb->evcb_cb_union.evcb_selfcb;
EVBASE_RELEASE_LOCK(base, th_base_lock);
evcb_selfcb(evcb, evcb->evcb_arg);
}
break;
case EV_CLOSURE_EVENT_FINALIZE:
case EV_CLOSURE_EVENT_FINALIZE_FREE: {
void (*evcb_evfinalize)(struct event *, void *);
int evcb_closure = evcb->evcb_closure;
EVUTIL_ASSERT(ev != NULL);
base->current_event = NULL;
evcb_evfinalize = ev->ev_evcallback.evcb_cb_union.evcb_evfinalize;
EVUTIL_ASSERT((evcb->evcb_flags & EVLIST_FINALIZING));
EVBASE_RELEASE_LOCK(base, th_base_lock);
evcb_evfinalize(ev, ev->ev_arg);
event_debug_note_teardown_(ev);
if (evcb_closure == EV_CLOSURE_EVENT_FINALIZE_FREE)
mm_free(ev);
}
break;
case EV_CLOSURE_CB_FINALIZE: {
void (*evcb_cbfinalize)(struct event_callback *, void *) = evcb->evcb_cb_union.evcb_cbfinalize;
base->current_event = NULL;
EVUTIL_ASSERT((evcb->evcb_flags & EVLIST_FINALIZING));
EVBASE_RELEASE_LOCK(base, th_base_lock);
evcb_cbfinalize(evcb, evcb->evcb_arg);
}
break;
default:
EVUTIL_ASSERT(0);
}
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
base->current_event = NULL;
#ifndef EVENT__DISABLE_THREAD_SUPPORT
if (base->current_event_waiters) {
base->current_event_waiters = 0;
EVTHREAD_COND_BROADCAST(base->current_event_cond);
}
#endif
// 如果中止標誌位設置,則中斷執行
if (base->event_break)
return -1;
// 如果當前執行的事件個數 大於 檢查新事件之間執行回調函數個數,則需要返回檢查新事件
if (count >= max_to_process)
return count;
// 如果執行的事件個數不爲零,且截止事件不爲空,則需要判定當前時間是否超過截止時間,如果超過,則退出執行;
if (count && endtime) {
struct timeval now;
update_time_cache(base);
gettime(base, &now);
if (evutil_timercmp(&now, endtime, >=))
return count;
}
if (base->event_continue)
break;
}
return count;
}
十二、event_signal_closure
/* "closure" function called when processing active signal events */
// 處理激活的信號事件時的調用函數
static inline void
event_signal_closure(struct event_base *base, struct event *ev)
{
short ncalls;
int should_break;
/* Allows deletes to work */
ncalls = ev->ev_ncalls;
if (ncalls != 0)
ev->ev_pncalls = &ncalls;
EVBASE_RELEASE_LOCK(base, th_base_lock);
// 根據事件調用次數循環調用信號事件回調函數
while (ncalls) {
ncalls--;
ev->ev_ncalls = ncalls;
if (ncalls == 0)
ev->ev_pncalls = NULL;
(*ev->ev_callback)(ev->ev_fd, ev->ev_res, ev->ev_arg);
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
should_break = base->event_break;
EVBASE_RELEASE_LOCK(base, th_base_lock);
if (should_break) {
if (ncalls != 0)
ev->ev_pncalls = NULL;
return;
}
}
}
十三、event_persist_closure
/* Closure function invoked when we're activating a persistent event. */
// 處理永久事件的回調函數
static inline void
event_persist_closure(struct event_base *base, struct event *ev)
{
void (*evcb_callback)(evutil_socket_t, short, void *);
// Other fields of *ev that must be stored before executing
evutil_socket_t evcb_fd;
short evcb_res;
void *evcb_arg;
/* reschedule the persistent event if we have a timeout. */
// 如果超時的話,需要重新安排永久事件
if (ev->ev_io_timeout.tv_sec || ev->ev_io_timeout.tv_usec) {
/* If there was a timeout, we want it to run at an interval of
* ev_io_timeout after the last time it was _scheduled_ for,
* not ev_io_timeout after _now_. If it fired for another
* reason, though, the timeout ought to start ticking _now_. */
// 如果有超時事件,並且想要它在上一次超時時間點ev_io_timeout間隔之後運行,而不是從現在的時間點之後的ev_io_timeout。如果不是超時時間,則需要從現在的時間點開始;
struct timeval run_at, relative_to, delay, now;
ev_uint32_t usec_mask = 0;
EVUTIL_ASSERT(is_same_common_timeout(&ev->ev_timeout,
&ev->ev_io_timeout));
gettime(base, &now);
// 如果使用公用超時隊列,則需要重新調整掩碼;
// 如果不使用公用超時隊列,則需要根據是否爲超時事件來決定下一次的超時時間從哪個時間點開始算起;
if (is_common_timeout(&ev->ev_timeout, base)) {
delay = ev->ev_io_timeout;
usec_mask = delay.tv_usec & ~MICROSECONDS_MASK;
delay.tv_usec &= MICROSECONDS_MASK;
if (ev->ev_res & EV_TIMEOUT) {
relative_to = ev->ev_timeout;
relative_to.tv_usec &= MICROSECONDS_MASK;
} else {
relative_to = now;
}
} else {
delay = ev->ev_io_timeout;
if (ev->ev_res & EV_TIMEOUT) {
relative_to = ev->ev_timeout;
} else {
relative_to = now;
}
}
// 獲取運行的超時時間,
// 並比較超時時間和當前時間;如果超時,則將事件重新添加到隊列中;
evutil_timeradd(&relative_to, &delay, &run_at);
if (evutil_timercmp(&run_at, &now, <)) {
/* Looks like we missed at least one invocation due to
* a clock jump, not running the event loop for a
* while, really slow callbacks, or
* something. Reschedule relative to now.
*/
evutil_timeradd(&now, &delay, &run_at);
}
run_at.tv_usec |= usec_mask;
event_add_nolock_(ev, &run_at, 1);
}
// Save our callback before we release the lock
evcb_callback = ev->ev_callback;
evcb_fd = ev->ev_fd;
evcb_res = ev->ev_res;
evcb_arg = ev->ev_arg;
// Release the lock
EVBASE_RELEASE_LOCK(base, th_base_lock);
// Execute the callback
(evcb_callback)(evcb_fd, evcb_res, evcb_arg);
}