Libevent源码剖析(二)之数据结构

描述Libevent中出现的数据结构:

struct event_base :

事件处理集合

struct event_base {
	const struct eventop *evsel;        //对struct event对象的操作函数,以指针函数的方式提供
	void *evbase;        //指向特定数据的指针
	struct event_changelist changelist;        //记录事件变化的列表,仅由O(1)方式使用

	const struct eventop *evsigsel;        //对struct event signal对象的处理,以指针函数的方式进行注册
	struct evsig_info sig;        //实现通用信号处理程序的代码

	int virtual_event_count;        //虚拟事件数量
	int virtual_event_count_max;        //最大的活动虚拟事件数量
	int event_count;        //添加到struct event_base中的事件总数
	int event_count_max;        //允许添加到struct event_base中的最大的事件数量
	int event_count_active;        //目前活动的事件总数
	int event_count_active_max;        //允许的活动事件总数

	int event_gotterm;        //标志:是否需要在事件处理结束后终止事件循环
	int event_break;           //标志:是否应该立即终止循环
	int event_continue;       //标志:是否应该立即启动一个新的事件循环
	int event_running_priority;        //当前正在运行的事件的优先级
	int running_loop;        //标志:是否运行event_base_loop函数,以防止可重入调用
	int n_deferreds_queued;        //标志:防止饥饿的手段

        #define TAILQ_HEAD(name, type)			\
        struct name {					\
	        struct type *tqh_first;			\
	        struct type **tqh_last;			\
        }
        //活动事件管理
	struct evcallback_list *activequeues;        //活动事件队列,so,evcallback_list很可能是使用了这种方式进行注册的
	int nactivequeues;        //活动事件队列的长度
	struct evcallback_list active_later_queue;        //下一次应该激活的事件队列

        //超时处理
	struct common_timeout_list **common_timeout_queues;        //常用的超时队列
	int n_common_timeouts;        //超时队列中的条目数
	int n_common_timeouts_allocated;        //超时队列占用的总大小

        //管理IO事件与信号事件,我就纳闷了,用红黑树管理不好吗?
	struct event_io_map io;        //从IO映射中添加的事件  
	struct event_signal_map sigmap;        //从信号映射中添加的事件
	
        struct min_heap timeheap;        //使用最小堆将超时事件组织起来
	struct timeval tv_cache;        //缓存系统时间,避免频繁的系统调用(gettimeofday,虽然说这个函数不陷入系统调用)
	struct evutil_monotonic_timer monotonic_timer;        //一个空的结构体,用途不明
	struct timeval tv_clock_diff;        //时钟差异(10ms?20ms?)
	time_t last_updated_clock_diff;        //最后一次更新事件的记录

	//多线程管理
	unsigned long th_owner_id;        //当前运行loop的thread id
	void *th_base_lock;        //线程锁,防止对event_base的访问冲突
	void *current_event_cond;        //条件变量,用于同步事件处理
	int current_event_waiters;        //阻塞在当前条件变量上的等待线程
	struct event_callback *current_event;        //正在执行的回调事件

	enum event_base_config_flag flags;        //这个event_base的配置标志

	struct timeval max_dispatch_time;        //一次事件循环的最大时间
	int max_dispatch_callbacks;        //一次事件循环中可以处理的最大 的回调函数
	int limit_callbacks_after_prio;        //回调函数中的优先级限制
        
        //通知主线程唤醒休息的线程
	int is_notify_pending;        //标志:struct event_base是否有等待处理的通知
	evutil_socket_t th_notify_fd[2];        //与主线程使用管道来进行交互,一般而言,会将主线程阻塞在read fd上
	struct event th_notify;        //使用事件处理的机制通知主线程,真的是:万物皆事件哇
	int (*th_notify_fn)(struct event_base *base);        //用于从子线程中唤醒主线程的回调函数

	struct evutil_weakrand_state weakrand_seed;        //随机数种子
	LIST_HEAD(once_event_list, event_once) once_events;        //保存目前尚未触发的通过event_once注册的事件
};

struct event

表示一个具体的事件对象,将IO,超时,信号三者统一起来

struct event {
	struct event_callback ev_evcallback;        //保存事件处理的回调函数,由必要的时候对这个事件进行填充,添加到合适的优先级队列

        //管理超时
	union {
		TAILQ_ENTRY(event) ev_next_with_common_timeout;        //我觉着这个有点复杂...直接标记在最小堆中的位置,岂不方便??
		int min_heap_idx;
	} ev_timeout_pos;
	evutil_socket_t ev_fd;        //关注的socket fd(int)
	struct event_base *ev_base;        //依赖的struct event_base对象

	union {
		struct {
			LIST_ENTRY (event) ev_io_next;        //在IO事件队列中的位置
			struct timeval ev_timeout;
		} ev_io;        //用于管理IO事件

		struct {
			LIST_ENTRY (event) ev_signal_next;        //在信号事件队列中的位置
			short ev_ncalls;        
			short *ev_pncalls;        //允许在回调中删除
		} ev_signal;        //用于管理超时事件
	} ev_;

	short ev_events;        //关注的事件
	short ev_res;		   //实际发生的事件 
	struct timeval ev_timeout;            //超时时间
};

struct eventop

struct event_base的操作

struct eventop {
	const char *name;        //这个后端的名称
	void *(*init)(struct event_base *);        //初始化struct event_base对象
	int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);        //将struct event对象添加到struct event_base对象中
	int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);        //将struct event对象从struct event_base中移除
	int (*dispatch)(struct event_base *, struct timeval *);        //将控制权提交给事件控制函数
	void (*dealloc)(struct event_base *);        //清理struct event_base中的对象
	int need_reinit;        //标志:是否需要在调用fork()函数后重新初始化事件库
	enum event_method_feature features;        //提供可以支持struct event_method_feature位数组的
	size_t fdinfo_len;        //为每一个fd维护的信息的长度
};

struct event_changelist

事件变化的列表,仅由O(1)方法使用

struct event_changelist {
	struct event_change *changes;        //链表
	int n_changes;        
	int changes_size;
};

struct event_change

struct event_change {
	evutil_socket_t fd;        //Libevent对socketfd,signal,timer的封装,(int)
	short old_events;        //fd之前上启用的事件

	ev_uint8_t read_change;    //此次改变发生的读事件
	ev_uint8_t write_change;    //此次改变发生的写事件
	ev_uint8_t close_change;    //此次改变发生的关闭事件
};

struct event_method_feature

enum event_method_feature {
    EV_FEATURE_ET = 0x01,
    EV_FEATURE_O1 = 0x02,
    EV_FEATURE_FDS = 0x04,
    EV_FEATURE_EARLY_CLOSE = 0x08
};

struct evsig_info

为信号处理函数提供事件

struct evsig_info {
	struct event ev_signal;        //为信号事件注册的一个struct event对象
	evutil_socket_t ev_signal_pair[2];        //使用进程间管道的方式处理信号事件
	int ev_signal_added;        //判断信号事件是否已经被添加
	int ev_n_signals_added;        //我们目前正在关注的信号数量
	struct sigaction **sh_old;        //保存一系列信号处理对象
	int sh_old_max;        //保存的信号处理对象的个数
}

struct common_timeout_list

处理超时事件

struct common_timeout_list {
	struct event_list events;        //当前队列中正在等待的事件列表
	struct timeval duration;        //表示事件的持续时间
	struct event timeout_event;        //每个队列都为超时时间准备了一个struct event对象
	struct event_base *base;        //这个struct event对象占用的
};

struct event_io_map

#define event_io_map event_signal_map
struct event_signal_map {
	void **entries;        //一个二维数据,数组中会维护一些信息
	int nentries;        //数组中的条目总数
};

struct event_callback

回调函数的封装

#ifndef TAILQ_ENTRY
#define EVENT_DEFINED_TQENTRY_
#define TAILQ_ENTRY(type)						\
struct {								\
	struct type *tqe_next;	/* next element */			\
	struct type **tqe_prev;	/* address of previous next element */	\
}
#endif 

struct event_callback {
	TAILQ_ENTRY(event_callback) evcb_active_next;        //回调事件队列中的一个成员
	short evcb_flags;    //根据flag选择合适的回调函数进行处理
	ev_uint8_t evcb_pri;	//标志这个事件的优先级
	ev_uint8_t evcb_closure;        
        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;        //回调函数使用的参数
};

struct event_config

为struct event_base提供配置对象

#define TAILQ_HEAD(name, type)			\
struct name {					\
	struct type *tqh_first;			\
	struct type **tqh_last;			\
}

struct event_config {
	TAILQ_HEAD(event_configq, event_config_entry) entries;        //双向链表

	int n_cpus_hint;        //cpus数量
	struct timeval max_dispatch_interval;        //最大的循环时间
	int max_dispatch_callbacks;        //最多的callbacks的调用
	int limit_callbacks_after_prio;        //优先级限制
	enum event_method_feature require_features;        //目前struct event_base支持的一些方法
	enum event_base_config_flag flags;
};

全局数据结构:eventops

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

posted on 2018-06-16 18:38  ukernel  阅读(288)  评论(0编辑  收藏  举报

导航