libevent源码分析(五)事件处理框架

事件处理框架event_base

正如我们在libevent源码分析(二) Reactor模式中提到的 R e a c t o r Reactor Reactor模式,其中包含事件源、 R e a c t o r Reactor Reactor框架、多路复用机制以及事件处理机制;而 e v e n t event event_ b a s e base base对应于 R e a c t o r Reactor Reactor模式中的 R e a c t o r Reactor Reactor框架。

l i b e v e n t libevent libevent中,对应为 e v e n t event event_ b a s e base base结构体,定义于 e v e n t − i n t e r n a l . h event-internal.h eventinternal.h文件:

struct event_base {
	//初始化Reactor的时候选择一种后端I/O复用机制,并记录在如下字段中
	const struct eventop *evsel;
	/**指向I/O复用机制真正存储的数据,它通过evsel成员的init函数来初始化 */
	void *evbase;

	/** 事件变化队列。其用途:如果一个文件描述符上注册的事件被多次修改,则可以使用缓冲来避免重复的系统调用(比如epoll_ctl)。它仅能用于时间复杂度为O(1)的I/O复用技术*/
	struct event_changelist changelist;

	/** 指向信号的后端处理机制 */
	const struct eventop *evsigsel;
	/** 信号事件处理器使用的数据结构*/
	struct evsig_info sig;

	/** 添加到该event_base的虚拟事件、激活事件和所有事件的数量*/
	int virtual_event_count;
	int virtual_event_count_max;
	int event_count;
	/** 添加到该event_base中的所有事件最大数量*/
	int event_count_max;
	/** Number of total events active in this event_base */
	int event_count_active;
	/** Maximum number of total events active in this event_base */
	int event_count_active_max;

	/** 是否执行完活动事件队列上剩余的任务之后就退出事件循环 */
	int event_gotterm;
	/** 是否立即退出事件循环*/
	int event_break;
	/** 是否启动一个新的事件循环 */
	int event_continue;

	/** 目前正在处理的活动事件队列的优先级*/
	int event_running_priority;

	/** 事件循环是否已经启动 */
	int running_loop;

	/** Set to the number of deferred_cbs we've made 'active' in the
	 * loop.  This is a hack to prevent starvation; it would be smarter
	 * to just use event_config_set_max_dispatch_interval's max_callbacks
	 * feature */
	int n_deferreds_queued;

	/* 活动事件队列数组 */
	/** 索引值越小的队列,优先级越高。高优先级的活动事件队列中的事件处理器将被优先处理
	 */
	struct evcallback_list *activequeues;
	/** 活动事件队列数组的大小 */
	int nactivequeues;
	/** 下一次处理事件变为活动的回调函数列表 */
	struct evcallback_list active_later_queue;

	/* 下面3个成员用于管理通用计时器队列 */

	/** An array of common_timeout_list* for all of the common timeout
	 * values we know. */
	struct common_timeout_list **common_timeout_queues;
	/** The number of entries used in common_timeout_queues */
	int n_common_timeouts;
	/** The total size of common_timeout_queues. */
	int n_common_timeouts_allocated;

	/** 文件描述符和I/O事件之间的映射关系 */
	struct event_io_map io;

	/** 信号值和信号事件之间的映射关系表. */
	struct event_signal_map sigmap;

	/** 时间堆 */
	struct min_heap timeheap;

	/** 管理系统时间的一些成员*/
	struct timeval tv_cache;

	struct evutil_monotonic_timer monotonic_timer;

	/** Difference between internal time (maybe from clock_gettime) and
	 * gettimeofday. */
	struct timeval tv_clock_diff;
	/** Second in which we last updated tv_clock_diff, in monotonic time. */
	time_t last_updated_clock_diff;

/*多线程支持*/
#ifndef EVENT__DISABLE_THREAD_SUPPORT
	/* threading support */
	/** 当前运行该event_base的事件循环的线程 */
	unsigned long th_owner_id;
	/** 对event_base的独占锁*/
	void *th_base_lock;
	/** 条件变量。用于唤醒正在等待某个事件处理完毕的线程. */
	void *current_event_cond;
	/** 等待current_event_cond的线程数*/
	int current_event_waiters;
#endif
	/** 正在执行其回调的事件 */
	struct event_callback *current_event;

#ifdef _WIN32
	/** IOCP support structure, if IOCP is enabled. */
	struct event_iocp_port *iocp;
#endif

	/** 该event_base的一些配置参数*/
	enum event_base_config_flag flags;

	struct timeval max_dispatch_time;
	int max_dispatch_callbacks;
	int limit_callbacks_after_prio;

	/* 下面这组成员变量给工作线程唤醒主线程提供了方法 */
	/** True if the base already has a pending notify, and we don't need
	 * to add any more. */
	int is_notify_pending;
	/** A socketpair used by some th_notify functions to wake up the main
	 * thread. */
	evutil_socket_t th_notify_fd[2];
	/** An event used by some th_notify functions to wake up the main
	 * thread. */
	struct event th_notify;
	/** A function used to wake up the main thread from another thread. */
	int (*th_notify_fn)(struct event_base *base);
};

(1) e v s e l evsel evsel e v b a s e evbase evbase看作是类和静态函数的关系,比如添加事件时的调用行为: e v s e l − > a d d ( e v b a s e , e v ) evsel->add(evbase, ev) evsel>add(evbase,ev),实际执行操作的是 e v b a s e evbase evbase;这相当于 c l a s s : : a d d ( i n s t a n c e , e v ) class::add(instance, ev) class::add(instance,ev) i n s t a n c e instance instance 就是 c l a s s class class 的一个对象实例。
e v s e l evsel evsel指向了全局变量 s t a t i c static static c o n s t const const s t r u c t struct struct e v e n t o p eventop eventop ∗ e v e n t o p s [ ] *eventops[] eventops[]中的一个;
前面也说过, l i b e v e n t libevent libevent将系统提供的 I / O I/O I/O d e m u l t i p l e x demultiplex demultiplex机制统一封装成了 e v e n t o p eventop eventop结构;因此 e v e n t o p s [ ] eventops[] eventops[]包含了 s e l e c t select select p o l l poll poll k e q u e u e kequeue kequeue e p o l l epoll epoll等等其中的若干个全局实例对象。
e v b a s e evbase evbase实际上是一个 e v e n t o p eventop eventop实例对象;
先来看看 e v e n t o p eventop eventop结构体,它的成员是一系列的函数指针, 在 e v e n t − i n t e r n a l . h event-internal.h eventinternal.h文件中:

struct eventop {
	/** 后端I/O复用技术的名称 */
	const char *name;
	/** 初始化函数 */
	void *(*init)(struct event_base *);
	/** 注册事件
	 */
	int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
	/** 删除事件 */
	int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
	/** 等待事件
	 */
	int (*dispatch)(struct event_base *, struct timeval *);
	/** 释放I/O复用机制使用的资源*/
	void (*dealloc)(struct event_base *);
	/** 程序调用fork之后是否需要重新初始化event_base
	 */
	int need_reinit;
	/**I/O复用技术支持的一些特性,可选如下3个值得按位或:EV_FEATURE_ET(支持边沿触发事件EV_ET)、EV_FEATURE_O1(事件检测算法的复杂度是O(1)和EV_FEATURE_FDS(不仅能监听socket上的事件,还能监听其它类型的文件描述符上的事件) */
	enum event_method_feature features;
	/** 有的I/O复用机制需要为每个I/O事件队列和信号事件队列分配额外的内存,以避免同一个文件描述符被重复插入I/O复用机制的事件表中。下面这个变量指定了这段内存的长度
	 */
	size_t fdinfo_len;
};

l i b e v e n t libevent libevent 中,每种 I / O I/O I/O d e m u l t i p l e x demultiplex demultiplex 机制的实现都必须提供这五个函数接口:
来完成自身的初始化、销毁释放、对事件的注册、注销和分发。

(2) l i b e v e n t libevent libevent提供的后端I/O复用技术,位于 e v e n t . c event.c event.c文件:

#ifdef EVENT__HAVE_EVENT_PORTS
extern const struct eventop evportops;
#endif
#ifdef EVENT__HAVE_SELECT
extern const struct eventop selectops;
#endif
#ifdef EVENT__HAVE_POLL
extern const struct eventop pollops;
#endif
#ifdef EVENT__HAVE_EPOLL
extern const struct eventop epollops;
#endif
#ifdef EVENT__HAVE_WORKING_KQUEUE
extern const struct eventop kqops;
#endif
#ifdef EVENT__HAVE_DEVPOLL
extern const struct eventop devpollops;
#endif
#ifdef _WIN32
extern const struct eventop win32ops;
#endif

/* Array of backends in order of preference. */
static const struct eventop *eventops[] = {
#ifdef EVENT__HAVE_EVENT_PORTS
	&evportops,
#endif
#ifdef EVENT__HAVE_WORKING_KQUEUE
	&kqops,
#endif
#ifdef EVENT__HAVE_EPOLL
	&epollops,
#endif
#ifdef EVENT__HAVE_DEVPOLL
	&devpollops,
#endif
#ifdef EVENT__HAVE_POLL
	&pollops,
#endif
#ifdef EVENT__HAVE_SELECT
	&selectops,
#endif
#ifdef _WIN32
	&win32ops,
#endif
	NULL
};

创建和初始化event_base

  • 创建一个 e v e n t event event_ b a s e base base 对象也既是创建了一个新的 l i b e v e n t libevent libevent 实例,程序需要通过调用 e v e n t event event_ i n i t ( ) init() init() e v e n t event event_ b a s e base base_ n e w new new()(内部调用 e v e n t event event_ b a s e base base_ n e w new new_ w i t h with with_ c o n f i g config config 函数执行具体操作)函数来创建,该函数同时还对新生成的 l i b e v e n t libevent libevent 实例进行了初始化。
  • 该函数首先为 e v e n t event event_ b a s e base base 实例申请空间,然后初始化 t i m e r timer timer m i n i − h e a p mini-heap miniheap,选择并初始化合适的系统 I / O I/O I/O d e m u l t i p l e x e r demultiplexer demultiplexer 机制,初始化各事件链表;
  • 函数还检测了系统的时间设置,为后面的时间管理打下基础。

接口函数

R e a c t o r Reactor Reactor 框架的作用就是提供事件的注册、注销接口;根据系统提供的事件多
路分发机制执行事件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数来处理事件。

L i b e v e n t Libevent Libevent中对应的接口函数主要是:

int event_add(struct event *ev, const struct timeval *tv); 
int event_del(struct event *ev); 
int event_base_loop(struct event_base *base, int loops); 
void event_active(struct event *event, int res, short events); 
void event_process_active(struct event_base *base);

本节将按介绍事件注册和删除的代码流程, l i b e v e n t libevent libevent 的事件循环框架将在下一节再具体描述。

(1)注册事件
函数原型:

int event_add(struct event *ev, const struct timeval *tv) 

参数: e v ev ev:指向要注册的事件;
t v tv tv:超时时间;
函数将 e v ev ev 注册到 e v − > e v ev->ev ev>ev_ b a s e base base 上,事件类型由 e v − > e v ev->ev ev>ev_ e v e n t s events events 指明,如果注册成功, e v ev ev将被插入到已注册链表中;如果 t v tv tv 不是 N U L L NULL NULL,则会同时注册定时事件,将 e v ev ev 添加到 t i m e r timer timer堆上;
如果其中有一步操作失败,那么函数保证没有事件会被注册,可以讲这相当于一个原子
操作。

int
event_add(struct event *ev, const struct timeval *tv)
{
	int res;

	if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
		event_warnx("%s: event has no event_base set.", __func__);
		return -1;
	}
	/*  防止多线程访问出错,加了锁,并且调用了event_add_internal函数*/
	EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);

	res = event_add_internal(ev, tv, 0);

	EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);

	return (res);
}

int
event_add_internal(struct event *ev, const struct timeval *tv,
    int tv_is_absolute)
{
	struct event_base *base = ev->ev_base;
	int res = 0;
	int notify = 0;

	EVENT_BASE_ASSERT_LOCKED(base);
	_event_debug_assert_is_setup(ev);

	event_debug((
		 "event_add: event: %p (fd "EV_SOCK_FMT"), %s%s%s%scall %p",
		 ev,
		 EV_SOCK_ARG(ev->ev_fd),
		 ev->ev_events & EV_READ ? "EV_READ " : " ",
		 ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
		 ev->ev_events & EV_CLOSED ? "EV_CLOSED " : " ",
		 tv ? "EV_TIMEOUT " : " ",
		 ev->ev_callback));

	EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));


	/*
	 *如果新添加的事件处理器是定时器,且它尚未被添加到通用定时器队列或时间堆中,则
	 *为定时器在时间堆上预留一个位置
	 */
	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 */
	}

	/* 如果当前调用者不是主线程(执行事件循环的线程), 并且被添加的事件处理器是信号
	 *事件处理器,而且主线程正在执行该信号事件处理器的回调函数,则当前调用者必须
	 *等待主线程完成调用,否则将引起竞态条件. */
#ifndef EVENT__DISABLE_THREAD_SUPPORT
	if (base->current_event == event_to_event_callback(ev) &&
	    (ev->ev_events & EV_SIGNAL)
	    && !EVBASE_IN_THREAD(base)) {
		++base->current_event_waiters;
		EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
	}
#endif

	if ((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL)) &&
	    !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
		if (ev->ev_events & (EV_READ|EV_WRITE))
			/*添加I/O事件和I/O事件处理器的映射关系 */
			res = evmap_io_add(base, ev->ev_fd, ev);
		else if (ev->ev_events & EV_SIGNAL)
			/*添加信号事件和信号事件处理器的映射关系*/
			res = evmap_signal_add(base, (int)ev->ev_fd, ev);
		if (res != -1)
			/*将事件处理器插入注册事件队列*/
			event_queue_insert(base, ev, EVLIST_INSERTED);
		if (res == 1) {
			/* 事件多路分发器中添加了新事件,通知主线程 */
			notify = 1;
			res = 0;
		}
	}

	/*
	 * 下面将事件处理器添加至通用计时器队列或时间堆中。对于信号事件处理器和I/O事件
	 * 处理器,根据evmap_*_add函数的结果决定是否添加(这是为了给事件设置超时);而对
	 * 于定时器,则始终应该添加之
	 */
	if (res != -1 && tv != NULL) {
		struct timeval now;
		int common_timeout;

		/*
		 * 对于永久性事件处理器,如果其超时时间不是绝对时间,则将该事件处理器的超
		 * 时时间记录在变量ev->ev_io_timeout中
		 */
		if (ev->ev_closure == EV_CLOSURE_EVENT_PERSIST && !tv_is_absolute)
			ev->ev_io_timeout = *tv;
		
		/*
		 *如果该事件处理器已经被插入通用定时器队列或时间堆中,则先删除它
		 */
		if (ev->ev_flags & EVLIST_TIMEOUT) {
			if (min_heap_elt_is_top(ev))
				notify = 1;
			event_queue_remove_timeout(base, ev);
		}


		/*
		 *如果待添加的事件处理器已经被激活,且原因是超时,则从活动事件队列中删
		 *除它,以避免其回调函数被执行。对于信号事件处理器,必要时还需将其ncalls
		 *成员设置为0.信号时间被触发时,ncalls指定其回调函数被执行的次数,将ncalls
		 *设置为0,可以干净地终止信号事件地处理
		 */
		if ((ev->ev_flags & EVLIST_ACTIVE) &&
		    (ev->ev_res & EV_TIMEOUT)) {
			if (ev->ev_events & EV_SIGNAL) {
				if (ev->ev_ncalls && ev->ev_pncalls) {
					*ev->ev_pncalls = 0;
				}
			}

			event_queue_remove(base, ev, EVLIST_ACTIVE);
		}

		gettime(base, &now);

		common_timeout = is_common_timeout(tv, base);

		if (tv_is_absolute) {
			ev->ev_timeout = *tv;
		/* 判断应该将定时器插入通用定时器队列,还是插入时间堆*/
		} else if (common_timeout) {
			struct timeval tmp = *tv;
			tmp.tv_usec &= MICROSECONDS_MASK;
			evutil_timeradd(&now, &tmp, &ev->ev_timeout);
			ev->ev_timeout.tv_usec |=
			    (tv->tv_usec & ~MICROSECONDS_MASK);
		} else {
			/*加上当前系统时间,以取得定时器超时地绝对时间*/
			evutil_timeradd(&now, tv, &ev->ev_timeout);
		}

		event_debug((
			 "event_add: event %p, timeout in %d seconds %d useconds, call %p",
			 ev, (int)tv->tv_sec, (int)tv->tv_usec, ev->ev_callback));
			 
		event_queue_insert(base, ev, EVLIST_TIMEOUT); //插入定时器
		
		/*如果被插入的事件处理器是通用定时器队列中的第一个元素,则通过调用common_timeout_schedule函数将其转移到时间堆中*/
		if (common_timeout) {
			struct common_timeout_list *ctl =
			    get_common_timeout_list(base, &ev->ev_timeout);
			if (ev == TAILQ_FIRST(&ctl->events)) {
				common_timeout_schedule(ctl, &now, ev);
			}
		} else {
			/* See if the earliest timeout is now earlier than it
			 * was before: if so, we will need to tell the main
			 * thread to wake up earlier than it would otherwise.
			 * We double check the timeout of the top element to
			 * handle time distortions due to system suspension.
			 */
			if (min_heap_elt_is_top(ev))
				notify = 1;
		}
	}

	/* 如果必要,唤醒主线程 */
	if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
		evthread_notify_base(base);

	_event_debug_note_add(ev);

	return (res);
}

e v e n t event event_ q u e u e queue queue_ i n s e r t insert insert():负责将事件插入到对应的链表中
e v e n t event event_ q u e u e queue queue_ r e m o v e remove remove():负责将事件从对应的链表中删除

void event_queue_insert(struct event_base *base, struct event *ev, 
int queue) 
{ 
	EVENT_BASE_ASSERT_LOCKED(base);

	// ev可能已经在激活列表中了,避免重复插入 
	if (ev->ev_flags & queue) { 
		if (queue & EVLIST_ACTIVE) 
			return; 
		
		event_errx(1. "%s: %p(fd %d) already on queue %x", __func__, 
				ev, ev->ev_fd, queue);
		return;
	} 
	
	if (~ev->ev_flags & EVLIST_INTERNAL)
		base->event_count++;  //将event_base拥有的事件处理器总数+1

	ev->ev_flags |= queue; // 记录queue标记 
	switch (queue) { 
		case EVLIST_INSERTED: // I/O或Signal事件,加入已注册事件链表 
			TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next); 
			break; 
		case EVLIST_ACTIVE: // 就绪事件,加入激活链表 
			base->event_count_active++; 
			TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], ev, 
								ev_active_next); 
			break; 
		//将定时器插入通用计时器队列或时间堆
		case EVLIST_TIMEOUT: {
			if (is_common_timeout(&ev->ev_timeout, base)) {
				struct common_timeout_list *ctl = 
						get_common_timeout_list(base, &ev->ev_timeout);
				insert_common_timeout_inorder(ctl, ev);
			} else
					min_heap_push(&base->timeheap, ev);
			break;
		}
		default:
				event_errx(1, "%s: unknown queue %x", __func__, queue);
	 } 
}

(2)删除事件
函数原型为:

int event_del(struct event *ev); 

该函数将删除事件 e v ev ev,对于 I / O I/O I/O 事件,从 I / O I/O I/O d e m u l t i p l e x e r demultiplexer demultiplexer 上将事件注销;对于 S i g n a l Signal Signal事件,将从 S i g n a l Signal Signal 事件链表中删除;对于定时事件,将从堆上删除;同样删除事件的操作则不一定是原子的,比如删除时间事件之后,有可能从系统 I / O I/O I/O 机制中注销会失败。

int
event_del(struct event *ev)
{
	int res;

	if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
		event_warnx("%s: event has no event_base set.", __func__);
		return -1;
	}

	EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
	res = event_del_internal(ev);
	EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);

	return (res);
}
static inline int
event_del_internal(struct event* ev)
{
	struct event_base *base;
	int res = 0, notify = 0;

	event_debug(("event_del: %p (fd "EV_SOCK_FMT"), callback %p",
		ev, EV_SOCK_ARG(ev->ev_fd), ev->ev_callback));

	/* ev_base为NULL,表明ev没有被注册 */
	if (ev->ev_base == NULL)
		return (-1);

	EVENT_BASE_ASSERT_LOCKED(ev->ev_base);
	base = ev->ev_base;

#ifndef _EVENT_DISABLE_THREAD_SUPPORT
	if (base->current_event == ev && !EVBASE_IN_THREAD(base)) {
		++base->current_event_waiters;
		EVTHREAD_COND_WAIT(base->current_event_cond, base_th_base_lock);
	}
#endif

	EVUTIL_ASSERT(!(ev->ev_flags &~EVLIST_ALL));
	
	//如果ev存在并且为信号事件则将ev_callback调用次数设置为0
	if (ev->ev_events & EV_SIGNAL) {
		if (ev->ev_ncalls && ev->ev_pncalls) {
			ev->ev_ncalls = 0;
		}
	}
	
	//从对应的链表中删除
	if (ev->ev_flags & EVLIST_TIMEOUT) {
		event_queue_remove(base, ev, EVLIST_TIMEOUT);
	}

	if (ev->ev_flags & EVLIST_ACTIVE)
		event_queue_remove_active(base, event_to_event_callback(ev));
	if (ev->ev_flags & EVLIST_INSERTED) {
		event_queue_remove_inserted(base, ev);
		if (ev->ev_events & (EV_READ|EV_WRITE))
			res = evmap_io_del(base, ev->ev_fd, ev);
		else
			res = evmap_signal_del(base, (int)ev->ev_fd, ev);
		if (res == 1) {
			/* evmap says we need to notify the main thread. */
			notify = 1;
			res = 0;
		}
	}

	/* 如果不是正确的线程,则需要重新开始循环 */
	if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
		evthread_notify_base(base);

	_event_debug_note_del(ev);

	return (res);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值