libevent部分源代码笔记 .

来源:互联网 发布:三维动画软件 编辑:程序博客网 时间:2024/05/16 09:07

http://blog.csdn.net/tricky1997/article/details/7385021

libevent的源代码间间断断的看了有一些时间了,重点一直在实现的细节,每段代码都能看得差不多但就是不知道整个流程是怎样的。

昨天偶然发现了张亮的源代码分析,花了十几分钟过了一遍,豁然开朗!如果对libevent有个整体认识,很容易看懂。下午重看了几个主要函数,一下就串起来了,随手做了做笔记。libevent虽然没那么精炼,相比于libev的实现,还是非常易读的。

这篇与张亮那篇不同,相当于对libevent的主要的几个函数部分做一个伪代码翻译,以后工作中如果需要细读的话,能尽快再拾起来。

只涉及到主要部分,也就是对事件I/O以及定时的实现。像其他的信号处理,bufferevent,http,dns等非重点部分不再仔细研究。libevent在这几个方面的实现不如它事件I/O的实现应用的那么广泛。

代码版本2.0.16。源代码中关于多线程支持,信号处理和windows部分可能会删掉。


event_base相关


event_base_new

{

获取默认cfg;

调用event_base_new_with_config

释放掉cfh;

}


[cpp] view plaincopyprint?
  1. struct event_base *  
  2. event_base_new(void)  
  3. {  
  4.     struct event_base *base = NULL;  
  5.     struct event_config *cfg = event_config_new();  
  6.     if (cfg) {  
  7.         base = event_base_new_with_config(cfg);  
  8.         event_config_free(cfg);  
  9.     }  
  10.     return base;  
  11. }  



event_base_new_with_config

{

mm_calloc分配内存;

检测是否支持CLOCK_MONOTONIC(因为定时器最好可以保持时间的单调性,之后可以看到如果系统支持clock_gettime(CLOCK_MONOTONIC,tp)将会比较方便);

gettime(见后文);

初始化time_heap;

初始化eventqueue;

初始化信号使用的pair,初始化多线程时使用的pair;

初始化deferred_queue;

将config的flag复制到event_base;

初始化event_io_map;(event_io_map有两种实现方式:基于hash表的;类似于event_signal_map的。当使用第二种时,event_io_map及相应的操作相当于event_sigal_map及其操作的别名)

初始化event_signal_map;

遍历全局变量eventops,找到适合的backend,调用其init函数(init函数里会调用处理信号的evsig_init(base)),保存backend使用的特定数据;

初始化优先级队列event_base_priority_init(见下文);

}


[cpp] view plaincopyprint?
  1. struct event_base *  
  2. event_base_new_with_config(const struct event_config *cfg)  
  3. {  
  4.     int i;  
  5.     struct event_base *base;  
  6.     int should_check_environment;  
  7.   
  8.     if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) {  
  9.         event_warn("%s: calloc", __func__);  
  10.         return NULL;  
  11.     }  
  12.     detect_monotonic();  
  13.     gettime(base, &base->event_tv);  
  14.   
  15.     min_heap_ctor(&base->timeheap);  
  16.     TAILQ_INIT(&base->eventqueue);  
  17.     base->sig.ev_signal_pair[0] = -1;  
  18.     base->sig.ev_signal_pair[1] = -1;  
  19.     base->th_notify_fd[0] = -1;  
  20.     base->th_notify_fd[1] = -1;  
  21.   
  22.     event_deferred_cb_queue_init(&base->defer_queue);  
  23.     base->defer_queue.notify_fn = notify_base_cbq_callback;  
  24.     base->defer_queue.notify_arg = base;  
  25.     if (cfg)  
  26.         base->flags = cfg->flags;  
  27.   
  28.     evmap_io_initmap(&base->io);  
  29.     evmap_signal_initmap(&base->sigmap);  
  30.     event_changelist_init(&base->changelist);  
  31.   
  32.     base->evbase = NULL;  
  33.   
  34.     should_check_environment =  
  35.         !(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));  
  36.   
  37.     for (i = 0; eventops[i] && !base->evbase; i++) {  
  38.         if (cfg != NULL) {  
  39.             /* determine if this backend should be avoided */  
  40.             if (event_config_is_avoided_method(cfg,  
  41.                 eventops[i]->name))  
  42.                 continue;  
  43.             if ((eventops[i]->features & cfg->require_features)  
  44.                 != cfg->require_features)  
  45.                 continue;  
  46.         }  
  47.   
  48.         /* also obey the environment variables */  
  49.         if (should_check_environment &&  
  50.             event_is_method_disabled(eventops[i]->name))  
  51.             continue;  
  52.   
  53.         base->evsel = eventops[i];  
  54.   
  55.         base->evbase = base->evsel->init(base);  
  56.     }  
  57.   
  58.     if (base->evbase == NULL) {  
  59.         event_warnx("%s: no event mechanism available",  
  60.             __func__);  
  61.         base->evsel = NULL;  
  62.         event_base_free(base);  
  63.         return NULL;  
  64.     }  
  65.   
  66.     if (evutil_getenv("EVENT_SHOW_METHOD"))  
  67.         event_msgx("libevent using: %s", base->evsel->name);  
  68.   
  69.     /* allocate a single active event queue */  
  70.     if (event_base_priority_init(base, 1) < 0) {  
  71.         event_base_free(base);  
  72.         return NULL;  
  73.     }  
  74.   
  75.     return (base);  
  76. }  


gettime

{

尝试从event_base的cache中获得时间;

如果use_monotonic==1,则通过clock_gettime(CLOCK_MONOTONIC, &ts)获得时间。并对base->tv_clock_diff和base->last_updated_clock_diff修正(它会在event_base_gettimeofday_cached中使用,这不重要,不细说了);

否则,evutil_gettimeofday(evutil_gettimeofday在非windows平台上一般直接对应系统的gettimeofday,在windows平台用_ftime实现);

}


[cpp] view plaincopyprint?
  1. static int  
  2. gettime(struct event_base *base, struct timeval *tp)  
  3. {  
  4.     EVENT_BASE_ASSERT_LOCKED(base);  
  5.   
  6.     if (base->tv_cache.tv_sec) {  
  7.         *tp = base->tv_cache;  
  8.         return (0);  
  9.     }  
  10.   
  11. #if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)  
  12.     if (use_monotonic) {  
  13.         struct timespec ts;  
  14.   
  15.         if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)  
  16.             return (-1);  
  17.   
  18.         tp->tv_sec = ts.tv_sec;  
  19.         tp->tv_usec = ts.tv_nsec / 1000;  
  20.         if (base->last_updated_clock_diff + CLOCK_SYNC_INTERVAL  
  21.             < ts.tv_sec) {  
  22.             struct timeval tv;  
  23.             evutil_gettimeofday(&tv,NULL);  
  24.             evutil_timersub(&tv, tp, &base->tv_clock_diff);  
  25.             base->last_updated_clock_diff = ts.tv_sec;  
  26.         }  
  27.   
  28.         return (0);  
  29.     }  
  30. #endif   
  31.   
  32.     return (evutil_gettimeofday(tp, NULL));  
  33. }  


event_base_priority_init

{

如果已经有active event,直接返回;

初始化event_base中npriorityies个队列指针以及数量;

}


[cpp] view plaincopyprint?
  1. int  
  2. event_base_priority_init(struct event_base *base, int npriorities)  
  3. {  
  4.     int i;  
  5.   
  6.     if (N_ACTIVE_CALLBACKS(base) || npriorities < 1  
  7.         || npriorities >= EVENT_MAX_PRIORITIES)  
  8.         return (-1);  
  9.   
  10.     if (npriorities == base->nactivequeues)  
  11.         return (0);  
  12.   
  13.     if (base->nactivequeues) {  
  14.         mm_free(base->activequeues);  
  15.         base->nactivequeues = 0;  
  16.     }  
  17.   
  18.     /* Allocate our priority queues */  
  19.     base->activequeues = (struct event_list *)  
  20.       mm_calloc(npriorities, sizeof(struct event_list));  
  21.     if (base->activequeues == NULL) {  
  22.         event_warn("%s: calloc", __func__);  
  23.         return (-1);  
  24.     }  
  25.     base->nactivequeues = npriorities;  
  26.   
  27.     for (i = 0; i < base->nactivequeues; ++i) {  
  28.         TAILQ_INIT(&base->activequeues[i]);  
  29.     }  
  30.   
  31.     return (0);  
  32. }  



 

在继续之前,插一下event_base中几个队列的性质。

EVLIST_INSERTED    一般的I/O event的队列       插入到eventqueue

EVLIST_TIMEOUT      定时的event 的队列            插入到time_heap或者common_timeout_list

EVLIST_ACTIVE          active event的队列             插入到activequeues

一个event可以被插入到不同队列中,例如带计时器的I/O event可以同时被放进eventqueue和time_heap。

event_count是这三种队列里event数量的总和。

基本上每个队列也都有各自的计数变量。


event相关

event_new

{

申请一块内存;

event_assign;

}

event_assign

{

参数赋值到event上;

ev->flags置为EVLIST_INIT;(ev->flags用来保存EVLIST_*这种标志,ev->res用来保存EV_*这种标志,后边会遇到)

switch(event的类型)

  EV_SIGNAL: ev->ev_closure = EV_CLOSURE_SIGNAL;

  EV_PERSIST: ev->ev_closure = EV_CLOSURE_PERSIST;

  其他: ev->ev_closure = EV_CLOSURE_NONE;

event优先级初始化为1/2 * base的优先级队列个数;

}


[cpp] view plaincopyprint?
  1. int  
  2. event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, shortvoid *), void *arg)  
  3. {  
  4.     if (!base)  
  5.         base = current_base;  
  6.   
  7.     _event_debug_assert_not_added(ev);  
  8.   
  9.     ev->ev_base = base;  
  10.   
  11.     ev->ev_callback = callback;  
  12.     ev->ev_arg = arg;  
  13.     ev->ev_fd = fd;  
  14.     ev->ev_events = events;  
  15.     ev->ev_res = 0;  
  16.     ev->ev_flags = EVLIST_INIT;  
  17.     ev->ev_ncalls = 0;  
  18.     ev->ev_pncalls = NULL;  
  19.   
  20.     if (events & EV_SIGNAL) {  
  21.         if ((events & (EV_READ|EV_WRITE)) != 0) {  
  22.             event_warnx("%s: EV_SIGNAL is not compatible with "  
  23.                 "EV_READ or EV_WRITE", __func__);  
  24.             return -1;  
  25.         }  
  26.         ev->ev_closure = EV_CLOSURE_SIGNAL;  
  27.     } else {  
  28.         if (events & EV_PERSIST) {  
  29.             evutil_timerclear(&ev->ev_io_timeout);  
  30.             ev->ev_closure = EV_CLOSURE_PERSIST;  
  31.         } else {  
  32.             ev->ev_closure = EV_CLOSURE_NONE;  
  33.         }  
  34.     }  
  35.   
  36.     min_heap_elem_init(ev);  
  37.   
  38.     if (base != NULL) {  
  39.         /* by default, we put new events into the middle priority */  
  40.         ev->ev_pri = base->nactivequeues / 2;  
  41.     }  
  42.   
  43.     _event_debug_note_setup(ev);  
  44.   
  45.     return 0;  
  46. }  


event_add_internal

{

如果有定时的话,在time_heap上预留一个位置;(time_heap使用的内存的分配采用了指数次扩展的方式,初始化一个值,每次不够用时^2一下。类似的策略在libevent里的多个队列中都可以看到使用)

如果是I/O或者信号而且不在active队列 {

对于I/O事件:evmap_io_add(见下文)

对于信号时间:evmap_signal_add

event_queue_insert(... EVLIST_INSERTED)(见下文)

}

如果插入正常而且有定时{

如果ev->ev_closure==EV_CLOSURE_PERSIST且使用了相对时间(比如,当我们正常调用event_add()时,我们可能将时间设为10s,这就是相对时间),就保存时间到union的另一个变量里;

如果已经在time_heap里或者active了,就先把它从相应队列里删掉;

event_queue_insert(... EVLIST_TIMEOUT);(见下文)

如果是个插入common_time_list的事件,调度一下。

}

}


[cpp] view plaincopyprint?
  1. static inline int  
  2. event_add_internal(struct event *ev, const struct timeval *tv,  
  3.     int tv_is_absolute)  
  4. {  
  5.     struct event_base *base = ev->ev_base;  
  6.     int res = 0;  
  7.     int notify = 0;  
  8.   
  9.     EVENT_BASE_ASSERT_LOCKED(base);  
  10.     _event_debug_assert_is_setup(ev);  
  11.   
  12.     event_debug((  
  13.          "event_add: event: %p (fd %d), %s%s%scall %p",  
  14.          ev,  
  15.          (int)ev->ev_fd,  
  16.          ev->ev_events & EV_READ ? "EV_READ " : " ",  
  17.          ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",  
  18.          tv ? "EV_TIMEOUT " : " ",  
  19.          ev->ev_callback));  
  20.   
  21.     EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));  
  22.   
  23.     /* 
  24.      * prepare for timeout insertion further below, if we get a 
  25.      * failure on any step, we should not change any state. 
  26.      */  
  27.     if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {  
  28.         if (min_heap_reserve(&base->timeheap,  
  29.             1 + min_heap_size(&base->timeheap)) == -1)  
  30.             return (-1);  /* ENOMEM == errno */  
  31.     }  
  32.   
  33.   
  34.     if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&  
  35.         !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {  
  36.         if (ev->ev_events & (EV_READ|EV_WRITE))  
  37.             res = evmap_io_add(base, ev->ev_fd, ev);  
  38.         else if (ev->ev_events & EV_SIGNAL)  
  39.             res = evmap_signal_add(base, (int)ev->ev_fd, ev);  
  40.         if (res != -1)  
  41.             event_queue_insert(base, ev, EVLIST_INSERTED);  
  42.         if (res == 1) {  
  43.             /* evmap says we need to notify the main thread. */  
  44.             notify = 1;  
  45.             res = 0;  
  46.         }  
  47.     }  
  48.   
  49.     /* 
  50.      * we should change the timeout state only if the previous event 
  51.      * addition succeeded. 
  52.      */  
  53.     if (res != -1 && tv != NULL) {  
  54.         struct timeval now;  
  55.         int common_timeout;  
  56.   
  57.         /* 
  58.          * for persistent timeout events, we remember the 
  59.          * timeout value and re-add the event. 
  60.          * 
  61.          * If tv_is_absolute, this was already set. 
  62.          */  
  63.         if (ev->ev_closure == EV_CLOSURE_PERSIST && !tv_is_absolute)  
  64.             ev->ev_io_timeout = *tv;  
  65.   
  66.         /* 
  67.          * we already reserved memory above for the case where we 
  68.          * are not replacing an existing timeout. 
  69.          */  
  70.         if (ev->ev_flags & EVLIST_TIMEOUT) {  
  71.             /* XXX I believe this is needless. */  
  72.             if (min_heap_elt_is_top(ev))  
  73.                 notify = 1;  
  74.             event_queue_remove(base, ev, EVLIST_TIMEOUT);  
  75.         }  
  76.   
  77.         /* Check if it is active due to a timeout.  Rescheduling 
  78.          * this timeout before the callback can be executed 
  79.          * removes it from the active list. */  
  80.         if ((ev->ev_flags & EVLIST_ACTIVE) &&  
  81.             (ev->ev_res & EV_TIMEOUT)) {  
  82.             if (ev->ev_events & EV_SIGNAL) {  
  83.                 /* See if we are just active executing 
  84.                  * this event in a loop 
  85.                  */  
  86.                 if (ev->ev_ncalls && ev->ev_pncalls) {  
  87.                     /* Abort loop */  
  88.                     *ev->ev_pncalls = 0;  
  89.                 }  
  90.             }  
  91.   
  92.             event_queue_remove(base, ev, EVLIST_ACTIVE);  
  93.         }  
  94.   
  95.         gettime(base, &now);  
  96.   
  97.         common_timeout = is_common_timeout(tv, base);  
  98.         if (tv_is_absolute) {  
  99.             ev->ev_timeout = *tv;  
  100.         } else if (common_timeout) {  
  101.             struct timeval tmp = *tv;  
  102.             tmp.tv_usec &= MICROSECONDS_MASK;  
  103.             evutil_timeradd(&now, &tmp, &ev->ev_timeout);  
  104.             ev->ev_timeout.tv_usec |=  
  105.                 (tv->tv_usec & ~MICROSECONDS_MASK);  
  106.         } else {  
  107.             evutil_timeradd(&now, tv, &ev->ev_timeout);  
  108.         }  
  109.   
  110.         event_debug((  
  111.              "event_add: timeout in %d seconds, call %p",  
  112.              (int)tv->tv_sec, ev->ev_callback));  
  113.   
  114.         event_queue_insert(base, ev, EVLIST_TIMEOUT);  
  115.         if (common_timeout) {  
  116.             struct common_timeout_list *ctl =  
  117.                 get_common_timeout_list(base, &ev->ev_timeout);  
  118.             if (ev == TAILQ_FIRST(&ctl->events)) {  
  119.                 common_timeout_schedule(ctl, &now, ev);  
  120.             }  
  121.         } else {  
  122.             /* See if the earliest timeout is now earlier than it 
  123.              * was before: if so, we will need to tell the main 
  124.              * thread to wake up earlier than it would 
  125.              * otherwise. */  
  126.             if (min_heap_elt_is_top(ev))  
  127.                 notify = 1;  
  128.         }  
  129.     }  
  130.   
  131.     /* if we are not in the right thread, we need to wake up the loop */  
  132.     if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))  
  133.         evthread_notify_base(base);  
  134.   
  135.     _event_debug_note_add(ev);  
  136.   
  137.     return (res);  
  138. }  


evmap_io_add

{

如果使用hash,先保证内存足够;

调用GET_IO_SLOT_AND_CTOR;(在是否使用hash时,会有不同的实现)

old指示之前是否有其他的event读写该fd;(用于changelist优化)

如果是第一个读或者写,res或上EV_READ/EV_WRITE;

res!=0时,表示之前这个fd没有读或写,调用evsel->add;

更新fd对应的slot里的nreads/nwrites;

将event插入fd对应的slot的events队列。

}


[cpp] view plaincopyprint?
  1. int  
  2. evmap_io_add(struct event_base *base, evutil_socket_t fd, struct event *ev)  
  3. {  
  4.     const struct eventop *evsel = base->evsel;  
  5.     struct event_io_map *io = &base->io;  
  6.     struct evmap_io *ctx = NULL;  
  7.     int nread, nwrite, retval = 0;  
  8.     short res = 0, old = 0;  
  9.     struct event *old_ev;  
  10.   
  11.     EVUTIL_ASSERT(fd == ev->ev_fd);  
  12.   
  13.     if (fd < 0)  
  14.         return 0;  
  15.   
  16. #ifndef EVMAP_USE_HT  
  17.     if (fd >= io->nentries) {  
  18.         if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1)  
  19.             return (-1);  
  20.     }  
  21. #endif  
  22.     GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init,  
  23.                          evsel->fdinfo_len);  
  24.   
  25.     nread = ctx->nread;  
  26.     nwrite = ctx->nwrite;  
  27.   
  28.     if (nread)  
  29.         old |= EV_READ;  
  30.     if (nwrite)  
  31.         old |= EV_WRITE;  
  32.   
  33.     if (ev->ev_events & EV_READ) {  
  34.         if (++nread == 1)  
  35.             res |= EV_READ;  
  36.     }  
  37.     if (ev->ev_events & EV_WRITE) {  
  38.         if (++nwrite == 1)  
  39.             res |= EV_WRITE;  
  40.     }  
  41.     if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff)) {  
  42.         event_warnx("Too many events reading or writing on fd %d",  
  43.             (int)fd);  
  44.         return -1;  
  45.     }  
  46.     if (EVENT_DEBUG_MODE_IS_ON() &&  
  47.         (old_ev = TAILQ_FIRST(&ctx->events)) &&  
  48.         (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) {  
  49.         event_warnx("Tried to mix edge-triggered and non-edge-triggered"  
  50.             " events on fd %d", (int)fd);  
  51.         return -1;  
  52.     }  
  53.   
  54.     if (res) {  
  55.         void *extra = ((char*)ctx) + sizeof(struct evmap_io);  
  56.         /* XXX(niels): we cannot mix edge-triggered and 
  57.          * level-triggered, we should probably assert on 
  58.          * this. */  
  59.         if (evsel->add(base, ev->ev_fd,  
  60.             old, (ev->ev_events & EV_ET) | res, extra) == -1)  
  61.             return (-1);  
  62.         retval = 1;  
  63.     }  
  64.   
  65.     ctx->nread = (ev_uint16_t) nread;  
  66.     ctx->nwrite = (ev_uint16_t) nwrite;  
  67.     TAILQ_INSERT_TAIL(&ctx->events, ev, ev_io_next);  
  68.   
  69.     return (retval);  
  70. }  


event_queue_insert

{

如果已经加入了某队列而且不是active队列,则返回;(允许插入active队列两次)

base->evnet_count++;

switch(类型):

  EVLIST_INSERTED: 插入到eventqueue

  EVLIST_ACTIVE: 插入到activequeues

  EVLIST_TIMEOUT: 插入到time_heap或者common_timeout_queues

}


[cpp] view plaincopyprint?
  1. static void  
  2. event_queue_insert(struct event_base *base, struct event *ev, int queue)  
  3. {  
  4.     EVENT_BASE_ASSERT_LOCKED(base);  
  5.   
  6.     if (ev->ev_flags & queue) {  
  7.         /* Double insertion is possible for active events */  
  8.         if (queue & EVLIST_ACTIVE)  
  9.             return;  
  10.   
  11.         event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,  
  12.                ev, ev->ev_fd, queue);  
  13.         return;  
  14.     }  
  15.   
  16.     if (~ev->ev_flags & EVLIST_INTERNAL)  
  17.         base->event_count++;  
  18.   
  19.     ev->ev_flags |= queue;  
  20.     switch (queue) {  
  21.     case EVLIST_INSERTED:  
  22.         TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);  
  23.         break;  
  24.     case EVLIST_ACTIVE:  
  25.         base->event_count_active++;  
  26.         TAILQ_INSERT_TAIL(&base->activequeues[ev->ev_pri],  
  27.             ev,ev_active_next);  
  28.         break;  
  29.     case EVLIST_TIMEOUT: {  
  30.         if (is_common_timeout(&ev->ev_timeout, base)) {  
  31.             struct common_timeout_list *ctl =  
  32.                 get_common_timeout_list(base, &ev->ev_timeout);  
  33.             insert_common_timeout_inorder(ctl, ev);  
  34.         } else  
  35.             min_heap_push(&base->timeheap, ev);  
  36.         break;  
  37.     }  
  38.     default:  
  39.         event_errx(1, "%s: unknown queue %x", __func__, queue);  
  40.     }  
  41. }  


event_queue_remove类似于event_queue_insert:

--base->event_count;

对应不同的类型,从不同的队列中删除



event_base_loop相关


event_base_loop

{

置running_loop = 1;

清空时间缓存;

设置信号处理相关的全局变量;

event_gotterm和event_break清0;

while(!done){

检测并相应event_gotterm和event_break;

修正时间timecorrect;(如果时间回滚,将time_heap的所有时间减去差)

如果有活动event或者指定标识EVLOOP_NONBLOCK,清空时间tv。否则计算一下要等待下一个定时事件发生的时间。

如果没有event,直接返回;

更新上次的base->event_tv;

清空时间缓存;

调用后端的dispatch函数;

更新时间缓存;

处理time_heap中已过期的event: timeout_process;(从time_heap中取出,放入activequeues,见下文)

如果有active event{

处理active event: event_process_active;(见下文)

如果标识有EVLOOP_ONCE,而且没有了active event,而且刚才处理了几个,那么可以done=1;

}否则,若指定NONBLOCK,也done-1;

}

}


[cpp] view plaincopyprint?
  1. int  
  2. event_base_loop(struct event_base *base, int flags)  
  3. {  
  4.     const struct eventop *evsel = base->evsel;  
  5.     struct timeval tv;  
  6.     struct timeval *tv_p;  
  7.     int res, done, retval = 0;  
  8.   
  9.     /* Grab the lock.  We will release it inside evsel.dispatch, and again 
  10.      * as we invoke user callbacks. */  
  11.     EVBASE_ACQUIRE_LOCK(base, th_base_lock);  
  12.   
  13.     if (base->running_loop) {  
  14.         event_warnx("%s: reentrant invocation.  Only one event_base_loop"  
  15.             " can run on each event_base at once.", __func__);  
  16.         EVBASE_RELEASE_LOCK(base, th_base_lock);  
  17.         return -1;  
  18.     }  
  19.   
  20.     base->running_loop = 1;  
  21.   
  22.     clear_time_cache(base);  
  23.   
  24.     if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)  
  25.         evsig_set_base(base);  
  26.   
  27.     done = 0;  
  28.   
  29.     base->event_gotterm = base->event_break = 0;  
  30.   
  31.     while (!done) {  
  32.         /* Terminate the loop if we have been asked to */  
  33.         if (base->event_gotterm) {  
  34.             break;  
  35.         }  
  36.   
  37.         if (base->event_break) {  
  38.             break;  
  39.         }  
  40.   
  41.         timeout_correct(base, &tv);  
  42.   
  43.         tv_p = &tv;  
  44.         if (!N_ACTIVE_CALLBACKS(base) && !(flags & EVLOOP_NONBLOCK)) {  
  45.             timeout_next(base, &tv_p);  
  46.         } else {  
  47.             /* 
  48.              * if we have active events, we just poll new events 
  49.              * without waiting. 
  50.              */  
  51.             evutil_timerclear(&tv);  
  52.         }  
  53.   
  54.         /* If we have no events, we just exit */  
  55.         if (!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {  
  56.             event_debug(("%s: no events registered.", __func__));  
  57.             retval = 1;  
  58.             goto done;  
  59.         }  
  60.   
  61.         /* update last old time */  
  62.         gettime(base, &base->event_tv);  
  63.   
  64.         clear_time_cache(base);  
  65.   
  66.         res = evsel->dispatch(base, tv_p);  
  67.   
  68.         if (res == -1) {  
  69.             event_debug(("%s: dispatch returned unsuccessfully.",  
  70.                 __func__));  
  71.             retval = -1;  
  72.             goto done;  
  73.         }  
  74.   
  75.         update_time_cache(base);  
  76.   
  77.         timeout_process(base);  
  78.   
  79.         if (N_ACTIVE_CALLBACKS(base)) {  
  80.             int n = event_process_active(base);  
  81.             if ((flags & EVLOOP_ONCE)  
  82.                 && N_ACTIVE_CALLBACKS(base) == 0  
  83.                 && n != 0)  
  84.                 done = 1;  
  85.         } else if (flags & EVLOOP_NONBLOCK)  
  86.             done = 1;  
  87.     }  
  88.     event_debug(("%s: asked to terminate loop.", __func__));  
  89.   
  90. done:  
  91.     clear_time_cache(base);  
  92.     base->running_loop = 0;  
  93.   
  94.     EVBASE_RELEASE_LOCK(base, th_base_lock);  
  95.   
  96.     return (retval);  
  97. }  


timeout_process

{

while(栈顶event过期){

从所有可能的队列中删掉event;

active_nonblock( ...  EV_TIMEOUT);(插入到active队列,并在ev_res中设置EV_TIMEOUT标识)

}

}


[cpp] view plaincopyprint?
  1. static void  
  2. timeout_process(struct event_base *base)  
  3. {  
  4.     /* Caller must hold lock. */  
  5.     struct timeval now;  
  6.     struct event *ev;  
  7.   
  8.     if (min_heap_empty(&base->timeheap)) {  
  9.         return;  
  10.     }  
  11.   
  12.     gettime(base, &now);  
  13.   
  14.     while ((ev = min_heap_top(&base->timeheap))) {  
  15.         if (evutil_timercmp(&ev->ev_timeout, &now, >))  
  16.             break;  
  17.   
  18.         /* delete this event from the I/O queues */  
  19.         event_del_internal(ev);  
  20.   
  21.         event_debug(("timeout_process: call %p",  
  22.              ev->ev_callback));  
  23.         event_active_nolock(ev, EV_TIMEOUT, 1);  
  24.     }  
  25. }  


event_process_active

{

从低优先级向高优先级队列依次调用event_process_active_single_queue;(见下文)

处理deferred callbacks;(deferredqueue用于bufferevent中,不再细说)

}


[cpp] view plaincopyprint?
  1. static int  
  2. event_process_active(struct event_base *base)  
  3. {  
  4.     /* Caller must hold th_base_lock */  
  5.     struct event_list *activeq = NULL;  
  6.     int i, c = 0;  
  7.   
  8.     for (i = 0; i < base->nactivequeues; ++i) {  
  9.         if (TAILQ_FIRST(&base->activequeues[i]) != NULL) {  
  10.             activeq = &base->activequeues[i];  
  11.             c = event_process_active_single_queue(base, activeq);  
  12.             if (c < 0)  
  13.                 return -1;  
  14.             else if (c > 0)  
  15.                 break/* Processed a real event; do not 
  16.                     * consider lower-priority events */  
  17.             /* If we get here, all of the events we processed 
  18.              * were internal.  Continue. */  
  19.         }  
  20.     }  
  21.   
  22.     event_process_deferred_callbacks(&base->defer_queue,&base->event_break);  
  23.     return c;  
  24. }  


event_process_active_single_queue

{

从头到尾:

如果是EV_PERSIST: 从active队列移出;否则,del_internel,从各个队列移出。

switch(ev_closure):

  SIGNAL:  event_signal_closure();

  PERSIST: event_persist_closure();(从新调度这个event,并调用callback)

  NONE: 释放掉锁,调用callback;

查看是否需要event_break;

}


[cpp] view plaincopyprint?
  1. static int  
  2. event_process_active_single_queue(struct event_base *base,  
  3.     struct event_list *activeq)  
  4. {  
  5.     struct event *ev;  
  6.     int count = 0;  
  7.   
  8.     EVUTIL_ASSERT(activeq != NULL);  
  9.   
  10.     for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {  
  11.         if (ev->ev_events & EV_PERSIST)  
  12.             event_queue_remove(base, ev, EVLIST_ACTIVE);  
  13.         else  
  14.             event_del_internal(ev);  
  15.         if (!(ev->ev_flags & EVLIST_INTERNAL))  
  16.             ++count;  
  17.   
  18.         event_debug((  
  19.              "event_process_active: event: %p, %s%scall %p",  
  20.             ev,  
  21.             ev->ev_res & EV_READ ? "EV_READ " : " ",  
  22.             ev->ev_res & EV_WRITE ? "EV_WRITE " : " ",  
  23.             ev->ev_callback));  
  24.   
  25.         switch (ev->ev_closure) {  
  26.         case EV_CLOSURE_SIGNAL:  
  27.             event_signal_closure(base, ev);  
  28.             break;  
  29.         case EV_CLOSURE_PERSIST:  
  30.             event_persist_closure(base, ev);  
  31.             break;  
  32.         default:  
  33.         case EV_CLOSURE_NONE:  
  34.             EVBASE_RELEASE_LOCK(base, th_base_lock);  
  35.             (*ev->ev_callback)(  
  36.                 (int)ev->ev_fd, ev->ev_res, ev->ev_arg);  
  37.             break;  
  38.         }  
  39.   
  40.         EVBASE_ACQUIRE_LOCK(base, th_base_lock);  
  41.   
  42.         if (base->event_break)  
  43.             return -1;  
  44.     }  
  45.     return count;  
  46. }  



 

有时间仔细看看libev。粗看了一眼,那源代码实在风骚!

 

原创粉丝点击