Libevent源码剖析二

libevnt中的事件处理器是event结构类型,主要封装了局柄,事件类型,回调函数,以及其他必要的标志和数据。该结构体在include/event2/event_struct.h文件中定义

event结构体

struct event {
	#if 0
	struct event_callback {
	TAILQ_ENTRY(event_callback) evcb_active_next;//活动事件队列
	short evcb_flags; 
	/*用于标记event信息的字段,表明其当前的状态,可能的指如下
		#define EVLIST_TIMEOUT	    0x01 //event 在 time堆中
		#define EVLIST_INSERTED	    0x02 // event在已注事件链表中
		#define EVLIST_SIGNAL	    0x04 // 未看使用
		#define EVLIST_ACTIVE	    0x08 // event在激活链表中
		#define EVLIST_INTERNAL	    0x10 // 内部使用标记
		#define EVLIST_ACTIVE_LATER 0x20
		#define EVLIST_FINALIZING   0x40 
		#define EVLIST_INIT	    0x80	// event已被初始化
	*/
	ev_uint8_t evcb_pri;	/* smaller numbers are higher priority */
	ev_uint8_t evcb_closure;
	/* allows us to adopt for different types of events */
        union {
		void (*evcb_callback)(evutil_socket_t, short, void *);
		void (*evcb_selfcb)(struct event_callback *, void *);
		void (*evcb_evfinalize)(struct event *, void *);
		void (*evcb_cbfinalize)(struct event_callback *, void *);
		} evcb_cb_union;
		void *evcb_arg; // 回调函数的参数
	};
	#endif
	//注册的回调函数
	struct event_callback ev_evcallback;
	
	
	/* for managing timeouts */
	union {
		TAILQ_ENTRY(event) ev_next_with_common_timeout; //定时器,通用定时器,不是存储在时间堆来管理的,而是使用效率更加高的链表中管理的。此成员指出了该定时器在通用定时器中的位置
		int min_heap_idx;	//指出了该定时器在时间堆中的位置
	} ev_timeout_pos;// 一个定时器是否是通用定时器取决与器超时值大小,参考event.c中的is_common_timeout函数
	evutil_socket_t ev_fd; //socket fd
	
	struct event_base *ev_base;
	//从属的Reactor(event_base)
	union {
		/* used for io events */
		struct {
			LIST_ENTRY (event) ev_io_next;
			struct timeval ev_timeout;
		} ev_io;	 //IO事件队列

		/* used by signal events */
		struct {
			LIST_ENTRY (event) ev_signal_next; // 串联成一个尾队列
			short ev_ncalls;	//Reactor需要执行多少此事件对于的事件处理器的回调函数
			/* Allows deletes in callback */
			short *ev_pncalls;	
		} ev_signal; //信号事件队列
	} ev_;
	#if 0
	Libevent使用IO事件队列具有相同文件描述符的事件处理器组织在一起。当fd上有就绪事件,事件多路分发器
	(epoll)将相关事件添加到活动事件队列中。信号事件队列的存在也是由于相同的原因
	#endif
	short ev_events;	//事件类型,分别是IO事件,定时器事件和信号
	#if 0
	#define EV_TIMEOUT 0x01
	#define EV_READ 0x02
	#define EV_WRITE 0x04
	#define EV_SIGNAL 0x08
	#define EV_PRESIST 0x10/*永久事件*/
	#endif
	short ev_res;		/* result passed to event callback */
	struct timeval ev_timeout;
};

Libevent 对 event的管理

libevent对event的管理主要从三个链表指针出发,每次有事件转变为就绪状态事件时,将其移至evcb_active_next队列中,调用其evcb_callback回调函数处理并且根据就绪fd和事件类型填充evcb_callback函数的参数

在这里插入图片描述

事件设置的接口函数

创建event对象:libevent提供的函数有 : event_set(),event_base_set(), event_priority_set()

void
event_set(struct event *ev, evutil_socket_t fd, short events,
	  void (*callback)(evutil_socket_t, short, void *), void *arg)
{
	int r;
	r = event_assign(ev, current_base, fd, events, callback, arg);
	EVUTIL_ASSERT(r == 0);
}

1.fd 文件描述符或者信号,定时事件为-1;
2.设置事件类型比如EV_READ|EV_PERSIST 等等
3.设置事件的回调以及参数arg
4.初始化其他字段,比如缺省的event_base和优先级

event_base_set(struct event_base *base, struct event *ev)
{
	/* Only innocent events may be assigned to a different base */
	if (ev->ev_flags != EVLIST_INIT)
		return (-1);

	event_debug_assert_is_setup_(ev);

	ev->ev_base = base;
	ev->ev_pri = base->nactivequeues/2;
	return (0);
}

设置event将要注册到event_base中;
如果一个进程中存在多个libevent实例,那么必须调用该函数为event设置不同的event_base

/*
 * Set's the priority of an event - if an event is already scheduled
 * changing the priority is going to fail.
 */
int
event_priority_set(struct event *ev, int pri)
{
	event_debug_assert_is_setup_(ev);

	if (ev->ev_flags & EVLIST_ACTIVE)
		return (-1);
	if (pri < 0 || pri >= ev->ev_base->nactivequeues)
		return (-1);

	ev->ev_pri = pri;

	return (0);
}

event_base

struct event_base {
	/** Function pointers and other data to describe this event_base's
	 * backend. */
	const struct eventop *evsel;
	/** Pointer to backend-specific data. */
	void *evbase;
    #if 0
    添加事件时的调用行为:evsel->add(evbase, ev),实际上执行操作的是evbase;evsel指向全局变量
    static const struct eventop *eventops[]中的一个
    struct eventop {
	/** The name of this backend. */
	const char *name;
	/** Function to set up an event_base to use this backend.  It should
	 * create a new structure holding whatever information is needed to
	 * run the backend, and return it.  The returned pointer will get
	 * stored by event_init into the event_base.evbase field.  On failure,
	 * this function should return NULL. */
	void *(*init)(struct event_base *);
	/** Enable reading/writing on a given fd or signal.  'events' will be
	 * the events that we're trying to enable: one or more of EV_READ,
	 * EV_WRITE, EV_SIGNAL, and EV_ET.  'old' will be those events that
	 * were enabled on this fd previously.  'fdinfo' will be a structure
	 * associated with the fd by the evmap; its size is defined by the
	 * fdinfo field below.  It will be set to 0 the first time the fd is
	 * added.  The function should return 0 on success and -1 on error.
	 */
	int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
	/** As "add", except 'events' contains the events we mean to disable. */
	int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
	/** Function to implement the core of an event loop.  It must see which
	    added events are ready, and cause event_active to be called for each
	    active event (usually via event_io_active or such).  It should
	    return 0 on success and -1 on error.
	 */
	int (*dispatch)(struct event_base *, struct timeval *);
	/** Function to clean up and free our data from the event_base. */
	void (*dealloc)(struct event_base *);
	/** Flag: set if we need to reinitialize the event base after we fork.
	 */
	int need_reinit;
	/** Bit-array of supported event_method_features that this backend can
	 * provide. */
	enum event_method_feature features;
	/** Length of the extra information we should record for each fd that
	    has one or more active events.  This information is recorded
	    as part of the evmap entry for each fd, and passed as an argument
	    to the add and del functions above.
	 */
	size_t fdinfo_len;
};
    #endif
	/** List of changes to tell backend about at next dispatch.  Only used
	 * by the O(1) backends. */
	struct event_changelist changelist;

	/** Function pointers used to describe the backend that this event_base
	 * uses for signals */
	const struct eventop *evsigsel;
	/** Data to implement the common signal handler code. */
	struct evsig_info sig;

	/** Number of virtual events */
	int virtual_event_count;
	/** Maximum number of virtual events active */
	int virtual_event_count_max;
	/** Number of total events added to this event_base */
	int event_count;
	/** Maximum number of total events added to this 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;

	/** Set if we should terminate the loop once we're done processing
	 * events. */
	int event_gotterm;
	/** Set if we should terminate the loop immediately */
	int event_break;
	/** Set if we should start a new instance of the loop immediately. */
	int event_continue;

	/** The currently running priority of events */
	int event_running_priority;

	/** Set if we're running the event_base_loop function, to prevent
	 * reentrant invocation. */
	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;

	/* Active event management. */
	/** An array of nactivequeues queues for active event_callbacks (ones
	 * that have triggered, and whose callbacks need to be called).  Low
	 * priority numbers are more important, and stall higher ones.
	 */
	struct evcallback_list *activequeues; // 保存了所有注册事件event指针
	/** The length of the activequeues array */
	int nactivequeues;
	/** A list of event_callbacks that should become active the next time
	 * we process events, but not this time. */
	struct evcallback_list active_later_queue;

	/* common timeout logic */

	/** 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;

	/** Mapping from file descriptors to enabled (added) events */
	struct event_io_map io;

	/** Mapping from signal numbers to enabled (added) events. */
	struct event_signal_map sigmap;

	/** Priority queue of events with timeouts. */
	struct min_heap timeheap;

	/** Stored timeval: used to avoid calling gettimeofday/clock_gettime
	 * too often. */
	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 */
	/** The thread currently running the event_loop for this base */
	unsigned long th_owner_id;
	/** A lock to prevent conflicting accesses to this event_base */
	void *th_base_lock;
	/** A condition that gets signalled when we're done processing an
	 * event with waiters on it. */
	void *current_event_cond;
	/** Number of threads blocking on current_event_cond. */
	int current_event_waiters;
#endif
	/** The event whose callback is executing right now */
	struct event_callback *current_event;

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

	/** Flags that this base was configured with */
	enum event_base_config_flag flags;

	struct timeval max_dispatch_time;
	int max_dispatch_callbacks;
	int limit_callbacks_after_prio;

	/* Notify main thread to wake up break, etc. */
	/** 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);

	/** Saved seed for weak random number generator. Some backends use
	 * this to produce fairness among sockets. Protected by th_base_lock. */
	struct evutil_weakrand_state weakrand_seed;

	/** List of event_onces that have not yet fired. */
	LIST_HEAD(once_event_list, event_once) once_events;

};

创建和初始化

创建了一个event_base对象也即使创建了一个libevent实例,通过调用event_init()内部调用event_base_new函数执行创建, 为event_base申请空间,初始化timer mini-heap,选择合适的系统IO的demultiplexer机制,初始化各种事件链表
函数还检测系统的时间设置,为后面的时间管理打下基础

接口函数

  1. 注册事件
    函数原型:
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;
	}

	EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);

	res = event_add_nolock_(ev, tv, 0);

	EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);

	return (res);
} 
  1. 删除事件原型为:int event_del(struct event *ev);
    删除事件ev,对于IO事件,从IOdemultiplexer上将事件注销;对于Signal来说,将其从Signal事件链表中删除;对于定时事件,将从堆上删除(删除操作不一定是原子操作,比如删除事件之后,有可能从系统的IO机制中注销失败)
static int
event_del_(struct event *ev, int blocking)
{
	int res;
	struct event_base *base = ev->ev_base;

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

	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
	res = event_del_nolock_(ev, blocking);
	EVBASE_RELEASE_LOCK(base, th_base_lock);

	return (res);
}

int
event_del(struct event *ev)
{
	return event_del_(ev, EVENT_DEL_AUTOBLOCK);
}

**总结:**分析了event_base这一重要结构体,初步看到了系统的IO复用机制的封装event_op结构,并且结合了源码堆注册和删除事件处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值