Preface preface

In this section, we'll expand the research on timing events. First, just look at the signal event section, let's see how it's integrated into I o ( or how to associate with event base ).

How to integrate timing events into the main loop

Because of seletc, poll, epoll, this kind of mechanism supports timing, so it's easier to integrate timing events into the main loop. We only need to register the timing events on a small root heap, and then calculate the maximum timeout for the mechanism based on the heap top ( the shortest.

In the main loop, there are such code:

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.





res = evsel->dispatch(base, evbase, tv_p);



A timeout_next used to calculate the maximum wait time for the primary loop, where tv_p is assigned to the wait time.
And then evsel->dispatch calls the specific wait function, such as epoll epoll_wait, the last parameter of the parameter is the time that timeout_next calculated. In this case, the epoll_wait wait isn't used for a timing event, but the timing event is handled together.

In this code, there are three core functions timeout_next, dispatch, timeout_process. Next, we'll introduce the first and last, where dispatch is placed on the sections of the I mechanism integration section.


static int

timeout_next(struct event_base *base, struct timeval **tv_p)


 struct timeval now;

 struct event *ev;

 struct timeval *tv = *tv_p;

 /* min_heap_top返回处于小根堆的堆顶的定时事件 */

 if ((ev = min_heap_top(&base->timeheap)) == NULL) {

 /* if no time-based events are active wait for I/O */


 *tv_p = NULL;

 return (0);



 if (gettime(base, &now) == -1)

 return (-1);


 * 比较当前最快超时的时间与当前时间

 * 小与等与:不用等待了,直接返回


 if (evutil_timercmp(&ev->ev_timeout, &now, <=)) {


 return (0);



 evutil_timersub(&ev->ev_timeout, &now, tv);

 assert(tv->tv_sec> = 0);

 assert(tv->tv_usec> = 0);

 event_debug(("timeout_next: in %ld seconds", tv->tv_sec));

 return (0);


The function of this function is to calculate the time required to wait, as follows:

  • Getting the fastest time out
  • Compare it to the current time
  • If it's less than the current time, the proof has been timed out, and the tv is 0, after returning, dispatch will soon activate it ( wait for 0 ).
  • If it's greater than the current time, it's proved that there's a time to wait and call the evutil_timersub function to make a subtraction, and assign the wait time to tv

A tv point to tv_p, and tv_p is used to specify a timeout for dispatch.



timeout_process(struct event_base *base)


 struct timeval now;

 struct event *ev;

 if (min_heap_empty(&base->timeheap))


 gettime(base, &now);


 while ((ev = min_heap_top(&base->timeheap))) {


 if (evutil_timercmp(&ev->ev_timeout, &now,> ))


 /* delete this event from the I/O queues */


 event_debug(("timeout_process: call %p",



 event_active(ev, EV_TIMEOUT, 1);



The logic of this function is also simple:

  • Compare the timeout of the event at the top of the heap to the current time
  • If it's greater than that, then the time of the isn't, then the remaining events of the heap can't be timed out.
  • If less than, verify that the event has met the activation condition ( timeout ) and activate it
  • Repeat to see if the new root heap top condition is met until no event is met or in the heap.


In this section, we know how the timing events are integrated together to let the main loop process, and look carefully at the two important functions of timeout_next and timeout_process, in the next section, we'll see the functions of the time management section, timeout_correct and time plus, get, and so on.

Copyright © 2011 Dowemo All rights reserved.    Creative Commons   AboutUs