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