libevent源码分析(10)--2.1.8--事件激活
来源:互联网 发布:四维彩超数据正常值 编辑:程序博客网 时间:2024/06/07 02:31
一、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_dispatchintevent_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 inttimeout_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 voidevent_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 intepoll_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上的特定事件类型的事件插入激活队列中
voidevmap_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:该事件需要激活的次数,主要是应对信号事件,某些信号事件可能会注册多次,所以需要激活多次voidevent_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_调用
intevent_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 voidevent_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 voidtimeout_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 intevent_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 intevent_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 voidevent_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 voidevent_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);}
阅读全文
0 0
- libevent源码分析(10)--2.1.8--事件激活
- libevent源码分析(7)--2.1.8--信号事件处理机制分析
- libevent源码分析(8)--2.1.8--事件申请与释放
- libevent源码分析(9)--2.1.8--事件注册和删除
- libevent源码分析之事件激活
- libevent源码分析(6)--2.1.8--创建和释放libevent句柄event_base的相关函数
- libevent源码分析(1)--2.1.8--标志信息
- libevent源码分析(4)--2.1.8--结构体struct event_config
- libevent源码分析(5)--2.1.8--libevent配置信息对象struct event_config的申请和释放函数分析
- Libevent源码分析(四)--- libevent事件机制
- libevent源码分析(2)--2.1.8--结构体 struct event和struct event_callback
- libevent源码分析(3)--2.1.8--结构体struct event_base和struct eventop
- Libevent-2.1.8源码分析——event_base(一)
- Libevent-2.1.8源码分析——event_base(二)
- libevent源码分析--事件处理框架
- libevent源码分析--事件处理框架
- libevent源码分析--I/O事件
- libevent源码分析--事件处理框架
- html中<a>标签的使用方法 设置锚点导航.发邮件.打电话......
- 多线程学习
- Android APK反编译
- 大敏子的第一篇博客
- value toDF is not a member of org.apache.spark.rdd.RDD[People]
- libevent源码分析(10)--2.1.8--事件激活
- Linux命令 find查找文件详解
- 早期(编译期)优化
- 显示一个井字游戏的棋盘
- python dir()
- 关联表、连接表与空间连接之前的区别与联系
- 设计模式:建造者模式
- hexo博客源码备份与恢复
- struts2中用OGNL表达式定义字符串常量与单个字符常量需要注意的一个小细节