`
simohayha
  • 浏览: 1386370 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

libevent源码浅析(一)

阅读更多
这里分析的是libevent-1.4.9。

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);
	}
}

5
0
分享到:
评论
3 楼 shaibiao 2009-02-17  
笨笨狗 写道

这大过节的不去陪MM,还写代码?囧


  呵呵!何必揭人家短,也可能是你以X人之心度君子之腹.
2 楼 笨笨狗 2009-02-16  
这大过节的不去陪MM,还写代码?囧
1 楼 climber2002 2009-02-15  
猥亵这个词用得很传神

相关推荐

Global site tag (gtag.js) - Google Analytics