Libevent(2.1.8)中的事件结构体
这里的libevent版本为 2.1.8 。 libevent中事件的结构体struct event,定义在event_struct.h 中, 这里我们简单看一下:
struct event { struct event_callback ev_evcallback; //事件的回调函数 /* for managing timeouts */ union { TAILQ_ENTRY(event) ev_next_with_common_timeout;// 链表形式管理定时 之前只用最小堆管理超时 int min_heap_idx; //最小堆 管理超时事件 } ev_timeout_pos;// 二选一 evutil_socket_t ev_fd; // io事件时为关心的文件描述符,信号事件时为信号值 struct event_base *ev_base;// 所属事件堆的实例 union { /* used for io events */ struct { LIST_ENTRY (event) ev_io_next; struct timeval ev_timeout; } ev_io; //这部分指io事件时 所关心的同一描述符下,所有IO事件的链表 /* used by signal events */ struct { LIST_ENTRY (event) ev_signal_next; short ev_ncalls; /* Allows deletes in callback */ short *ev_pncalls; } ev_signal;//同一信号下信号事件链表 } ev_; short ev_events; //事件的类型 可读可写 超时等 short ev_res; /* result passed to event callback */ struct timeval ev_timeout; //事件超时时间 };
这里可以看到这个版本下的event 结构体比之前的好像少了不少东西, 如之前的结构:
//event提供了函数接口,供Reactor在事件发生时调用,以执行相应的事件处理, //通常它会绑定一个有效的句柄(ev_fd)做为回调函数的参数. struct event { //已注册事件队列入口 TAILQ_ENTRY (event) ev_next; //已激活事件队列入口 TAILQ_ENTRY (event) ev_active_next; //信号事件队列入口 不过在以前的分析中可以看到,将来这个队列中的内容会被添加到ev_active_next队列中。 TAILQ_ENTRY (event) ev_signal_next; //表示该event在定时器事件最小堆min_heap的索引 unsigned int min_heap_idx; /* for managing timeouts */ //该事件所属的反应堆实例 struct event_base *ev_base; //对于I/O事件,是绑定的文件描述符; 对于signal事件,是绑定的信号. int ev_fd; //表示事件类型: I/O,定时器或者信号 short ev_events; //事件就绪执行时,将要调用ev_callback 的次数,通常为1 short ev_ncalls; //该事件的超时时间,在定时器最小堆min_heap操作中作为节点值进行比较. struct timeval ev_timeout; //该事件的优先级,越小越优先. int ev_pri; /* smaller numbers are higher priority */ //该事件被激活时的回调函数 void (*ev_callback)(int, short, void *arg); //该事件的标记信息,表示其当前的状态,即它在哪个链表中 int ev_flags; ... //其他成员. };
这里可以看到在老版本的libevent 中event结构体中有回调函数, 参数,优先级参数, 新版本中都被定义在了struct event_callback ev_evcallback;中 如下:
struct event_callback { TAILQ_ENTRY(event_callback) evcb_active_next; short evcb_flags; //选择回调类型 由以下四种 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; };
比起老版本 新版本又丢弃了TAILQ_ENTRY(event) ev_next; 已注册事件队列入口 ev_active_next 已激活队列入口 ev_signal_next 信号事件队列入口等结构。
Libevent 事件堆实例结构体:
新版本的struct base_event 如下:
struct event_base { /** Function pointers and other data to describe this event_base's * backend. */ const struct eventop *evsel;//具体事件处理模型结构(select /poll/epoll)指针 /** Pointer to backend-specific data. */ void *evbase;//指向IO复用的真正操作 通过evsel来初始化 /** 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 handelr 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; //当前running 事件的优先级 /** Set if we're running the event_base_loop function, to prevent * reentrant invocation. */ int running_loop; //是否正在loop event /** 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. */
//已激活的回调事件队列 即event_callback 结构的队列 struct evcallback_list *activequeues; /** 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;//存储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; /** Flags that this base was configured with */
//这里后续的event config 会讲到 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. */
//多线程 主线程loop过程中一般会阻塞
//若这时添加或者删除事件的话, 就需要唤醒阻塞的主线程, 加入了一个未决状态 /** 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; };
对于事件的存储 老版本中用队列来存储, 在新版本中使用哈希表map 如event_io_map , event_signal_map结构。还有一些多线程支持的参数后续会看到它们的用途。后续还会详细解释其中的各个字段含义。