浏览 5075 次
锁定老帖子 主题:libevent源码浅析(一)
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-02-14
最后修改:2009-05-15
PS:前面还看了libev的源代码,妈的,那代码写的太猥亵了,相比较libevent代码写的好多了。。 首先来看一下最主要的几个数据结构: eventop结构体是所有事件驱动模型的基类。所有的io复用类型都会实现此结构体里各种方法。 struct eventop { const char *name; ///<事件驱动名称 void *(*init)(struct event_base *); //<初始化 int (*add)(void *, struct event *); ///<加入新的事件监测 int (*del)(void *, struct event *); ///<从事件监测中删除某一事件 int (*dispatch)(struct event_base *, void *, struct timeval *);///<启动此事件监测 void (*dealloc)(struct event_base *, void *); ///<释放此事件驱动的资源 /* set if we need to reinitialize the event base */ int need_reinit; ///<标志位 }; event_base管理所有的event对象,它包含了一些全部变量,比如事件驱动引擎evsel等。所有的event对象都会包含这个结构体。 struct event_base { const struct eventop *evsel; ///<事件驱动引擎 void *evbase; ///<事件驱动引擎的全局数据,在每一个事件引擎文件中定义,下面会介绍. int event_count; /* counts number of total events */ int event_count_active; /* counts number of active events */ int event_gotterm; /* Set to terminate loop */ int event_break; /* Set to terminate loop immediately */ /* active event management */ struct event_list **activequeues; ///<激活队列 int nactivequeues; ///<激活队列数目 /* signal handling info */ struct evsignal_info sig; ///<信号 struct event_list eventqueue; ///<全部事件队列 struct timeval event_tv; struct min_heap timeheap; ///<这里libevent将定时器队列实现为一个最小堆,也就是为了每次都把时间最晚的定时器能取出来,然后实现超时。更其实算法很简单,想要详细的了解可以去看下算法导论的第六章的Priority queues. struct timeval tv_cache; }; event结构表示每个事件,包含了一些事件私有的数据,比如回调函数等。。这里事件链表它使用了tail queue. struct event { TAILQ_ENTRY (event) ev_next; ///<下一个事件 TAILQ_ENTRY (event) ev_active_next; ///<下一个激活事件 TAILQ_ENTRY (event) ev_signal_next; ///<下一个信号事件列表 unsigned int min_heap_idx; /* for managing timeouts */ struct event_base *ev_base; ///<全局的base int ev_fd; ///<所需要监测的事件句柄 short ev_events; short ev_ncalls; short *ev_pncalls; /* Allows deletes in callback */ struct timeval ev_timeout; ///<超时时间 int ev_pri; /* smaller numbers are higher priority */ void (*ev_callback)(int, short, void *arg); ///<回调函数 void *ev_arg; ///<传递给回调函数的参数 int ev_res; /* result passed to event callback */ int ev_flags; }; 下面来介绍一下事件引擎中的两个结构,这里主要介绍下select,其他的几本类似. selectop是全局的select数据结构,也就是上面event_base数据结构中evbase的值,我们通过avbase就可以操作select的数据结构 struct selectop { int event_fds; /* Highest fd in fd set */ int event_fdsz; fd_set *event_readset_in; fd_set *event_writeset_in; fd_set *event_readset_out; fd_set *event_writeset_out; struct event **event_r_by_fd; struct event **event_w_by_fd; }; selectops也就是实现了eventop。它导出了select的接口。 const struct eventop selectops = { "select", select_init, select_add, select_del, select_dispatch, select_dealloc, 0 }; 我们再来看下几个重要的函数(其中省略了一些语句,只介绍重要的一些语句): struct event_base * event_base_new(void) { ...................................... //前面就是一些初始化,最重要的部分是下面的这个for循环。在这里初始化事件驱动引擎。这里eventops是一个eventop数组,里面包含所有事件驱动引擎的接口(就像上面介绍的selectops结构) for (i = 0; eventops[i] && !base->evbase; i++) { base->evsel = eventops[i]; ///下面调用初始化函数,返回每个事件引擎的全局数据结构 base->evbase = base->evsel->init(base); } .................................. /* allocate a single active event queue */ event_base_priority_init(base, 1); return (base); } event_init将event_base_new返回的值付给一个全局的变量current_base struct event_base * event_init(void) { struct event_base *base = event_base_new(); if (base != NULL) current_base = base; return (base); } event_add加一新的事件到当前事件引擎 int event_add(struct event *ev, const struct timeval *tv) { ///取得当前事件的一些有用的数据结构。 struct event_base *base = ev->ev_base; const struct eventop *evsel = base->evsel; void *evbase = base->evbase; int res = 0; /* * prepare for timeout insertion further below, if we get a * failure on any step, we should not change any state. */ if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) { if (min_heap_reserve(&base->timeheap, 1 + min_heap_size(&base->timeheap)) == -1) return (-1); /* ENOMEM == errno */ } ///这里调用evsel->add来加一事件到当前的事件引擎。 if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) && !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) { res = evsel->add(evbase, ev); if (res != -1) event_queue_insert(base, ev, EVLIST_INSERTED); } /* * we should change the timout state only if the previous event * addition succeeded. */ if (res != -1 && tv != NULL) { struct timeval now; /* * we already reserved memory above for the case where we * are not replacing an exisiting timeout. */ //如果超时就先删除此事件。 if (ev->ev_flags & EVLIST_TIMEOUT) event_queue_remove(base, ev, EVLIST_TIMEOUT); /* Check if it is active due to a timeout. Rescheduling * this timeout before the callback can be executed * removes it from the active list. */ if ((ev->ev_flags & EVLIST_ACTIVE) && (ev->ev_res & EV_TIMEOUT)) { /* See if we are just active executing this * event in a loop */ if (ev->ev_ncalls && ev->ev_pncalls) { /* Abort loop */ *ev->ev_pncalls = 0; } event_queue_remove(base, ev, EVLIST_ACTIVE); } gettime(base, &now); //计算超时时间并赋值给ev_timeout evutil_timeradd(&now, tv, &ev->ev_timeout); event_debug(( "event_add: timeout in %ld seconds, call %p", tv->tv_sec, ev->ev_callback)); //将此定时器加入定时器最小堆。 event_queue_insert(base, ev, EVLIST_TIMEOUT); } return (res); } loop函数将进入事件监测循环。 int event_base_loop(struct event_base *base, int flags) { ............................................ ....................................... ///校准时间,非Monotonic时钟这个函数将会立即返回。 timeout_correct(base, &tv); tv_p = &tv; 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. */ evutil_timerclear(&tv); } /* If we have no events, we just exit */ if (!event_haveevents(base)) { event_debug(("%s: no events registered.", __func__)); return (1); } /* update last old time */ gettime(base, &base->event_tv); /* clear time cache */ base->tv_cache.tv_sec = 0; ///调用相应的事件引擎处理函数 res = evsel->dispatch(base, evbase, tv_p); if (res == -1) return (-1); gettime(base, &base->tv_cache); ///超时处理函数(下面紧接着会介绍) timeout_process(base); if (base->event_count_active) { event_process_active(base); if (!base->event_count_active && (flags & EVLOOP_ONCE)) done = 1; } else if (flags & EVLOOP_NONBLOCK) done = 1; } .................................................. } 超时处理函数 void timeout_process(struct event_base *base) { struct timeval now; struct event *ev; if (min_heap_empty(&base->timeheap)) return; gettime(base, &now); ///遍历定时器 while ((ev = min_heap_top(&base->timeheap))) { if (evutil_timercmp(&ev->ev_timeout, &now, >)) break; /* delete this event from the I/O queues */ event_del(ev); event_debug(("timeout_process: call %p", ev->ev_callback)); ///激活此事件 event_active(ev, EV_TIMEOUT, 1); } } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-02-15
猥亵这个词用得很传神
|
|
返回顶楼 | |
发表时间:2009-02-16
这大过节的不去陪MM,还写代码?囧
|
|
返回顶楼 | |
发表时间:2009-02-17
笨笨狗 写道 这大过节的不去陪MM,还写代码?囧 呵呵!何必揭人家短,也可能是你以X人之心度君子之腹. |
|
返回顶楼 | |