描述Libevent中出现的数据结构:后端
事件处理集合数组
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注册的事件 };
表示一个具体的事件对象,将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 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维护的信息的长度 };
事件变化的列表,仅由O(1)方法使用多线程
struct event_changelist { struct event_change *changes; //链表 int n_changes; int changes_size; };
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; //这次改变发生的关闭事件 };
enum event_method_feature { EV_FEATURE_ET = 0x01, EV_FEATURE_O1 = 0x02, EV_FEATURE_FDS = 0x04, EV_FEATURE_EARLY_CLOSE = 0x08 };
为信号处理函数提供事件socket
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 event_list events; //当前队列中正在等待的事件列表 struct timeval duration; //表示事件的持续时间 struct event timeout_event; //每一个队列都为超时时间准备了一个struct event对象 struct event_base *base; //这个struct event对象占用的 };
#define event_io_map event_signal_map struct event_signal_map { void **entries; //一个二维数据,数组中会维护一些信息 int nentries; //数组中的条目总数 };
回调函数的封装oop
#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_base提供配置对象ui
#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; };
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 };