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

爲信號處理函數提供事件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 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

回調函數的封裝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_config

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

全局數據結構: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
};
相關文章
相關標籤/搜索