libevent主要數據結構

通用結構體

#define TAILQ_ENTRY(type)            \
struct {                                \
    struct type *tqe_next;  /* next element */       \
    struct type **tqe_prev; /* previous element */  \
}
放置在event結構體中,將event串成隊列。

#define TAILQ_HEAD(name, type)           \
struct name {                               \
    struct type *tqh_first; /* 隊列頭*/      \
    struct type **tqh_last; /* 隊列尾 */     \
}

event_base

event_base 代表一個libevent實體。其結構如下:

struct event_base {
    const struct eventop *evsel;  /* evbase對應的操作函數 */
    void *evbase;                 /* 採用何種IO多路複用函數 */
    
    int event_count;         /* 事件總量 */
    int event_count_active;  /* 激活事件數量 */

    int event_gotterm;      /* 優雅的結束,處理完激活事件隊列中事件後結束 */
    int event_break;        /* 立即結束 */

    
    struct event_list **activequeues; /* 多個激活事件隊列 */
    int nactivequeues;                /* 隊列個數,0最高優先級 */

    struct evsignal_info sig;         /* 信號結構體 */
    struct event_list eventqueue;     /* 信號/IO事件隊列 */
    struct min_heap timeheap;         /* 時間堆 */

    struct timeval tv_cache;          /* 緩存時間 */
    struct timeval event_tv;          /* 事件時間 */
};
1.  evsel 與 evbase

 evsel 代表操作集合。

const struct eventop epollops = {
	"epoll",
	epoll_init,
	epoll_add,
	epoll_del,
	epoll_dispatch,
	epoll_dealloc,
	1 /* need reinit */
};
evbase 代表採用哪種IO多路複用函數, epoll, select, poll等。
struct epollop {
	struct evepoll *fds;
	int nfds;
	
	struct epoll_event *events;
	int nevents;
	
	int epfd;
};
上述兩者配對使用,evbase 相當於C++的this指針,而epollops內的函數相當於類的成員函數。


2. activequeues

    activequeues隊列是一個指針數組,數組中每個元素可以指向一個事件隊列;數組索引表示優先級,0代表最高優先級。

當處理事件時候,從頭掃描數組,若發現非空事件隊列,進行處理,只有當前優先級隊列處理完成後,才進行下一優先級的處理。


3. sig、eventqueue、timeheap

    上述三個變量分別用於處理信號事件,信號與IO事件隊列,定時器事件小根堆。


4. tv_cache 、 event_tv

    由於獲取時間需要調用系統調用,這是一個耗時操作,因此libevent將時間緩存,減少系統調用次數,從而達到加速的目的。

event_tv 用於修正時間,後續時間管理章節說明。


event

struct event {
    TAILQ_ENTRY (event) ev_next;        /* IO、信號事件結點 */
    TAILQ_ENTRY (event) ev_active_next; /* 激活事件結點 */
    TAILQ_ENTRY (event) ev_signal_next; /* 信號事件結點 */
    unsigned int min_heap_idx;          /* 時間堆中索引位置 */

    struct event_base *ev_base;         /* 指向event_base 結構體 */

    int ev_fd;             /* 用戶套接字 或 信號*/
    short ev_events;       /* 事件類型,可讀,可寫,持久,超時 */
    short ev_ncalls;       /* 事件回調函數需要被調用次數 */
    short *ev_pncalls;     /* Allows deletes in callback */

    struct timeval ev_timeout; /* 超時時刻 */

    int ev_pri;                /* 事件優先級,0最高優先級 */

    void (*ev_callback)(int, short, void *arg);/* 事件回調函數 */
    void *ev_arg; /* 回調函數參數 */

    int ev_res;     /* result passed to event callback */
    int ev_flags;   /* 事件目前狀態, TIMEOUT, INIT, SIGNAL */
};

1. ev_next、ev_active_next、ev_singal_next、min_head_idx

    上述四個變量比較易於理解,分別是事件在不同隊列中的一個節點。有一個奇怪點,信號事件既在ev_next中,

又在ev_signal_next中。當用戶添加信號事件的時候,會在事件隊列中添加,同時,也會在該信號對應的隊列中添加。

允許同一信號,註冊不同的事件,這樣signal[sig no] 將會掛一個鏈表,如下圖。詳細內容在信號一節中說明。

j

(圖片來自互聯網)

2. ev_events

#define EV_TIMEOUT	0x01
#define EV_READ		0x02
#define EV_WRITE	0x04
#define EV_SIGNAL	0x08
#define EV_PERSIST	0x10	/* Persistant event */
在添加事件的時候指定事件類型,如果非持久事件,則事件在處理後被刪除。

3. ev_flags

#define EVLIST_TIMEOUT	0x01
#define EVLIST_INSERTED	0x02
#define EVLIST_SIGNAL	0x04
#define EVLIST_ACTIVE	0x08
#define EVLIST_INTERNAL	0x10
#define EVLIST_INIT	0x80
當前事件在內部的狀態,是否已經超時,是否已經插入事件隊列等等。

4. ev_ncalls

    運行一個事件的回調函數被調用ev_ncalls次, 主要是用來記錄信號,即同一事件對應的信號在一定時間內發生了n次,

則調用該事件回調函數n次。


5. ev_timeout

    如果該事件爲一個超時事件,那麼ev_timeout記錄該事件超時的時間點。比如當前時間是1:40, 那麼用戶指定10分鐘後超時,

則ev_timeout爲1:50.


6. ev_res

    該參數傳遞給用戶註冊的事件回調函數,告訴用戶,該事件是由於響應了什麼事件而被激活的。例如:

if (evread != NULL)
    event_active(evread, EV_READ, 1);
在epoll中,若一個事件可讀,通過event_active將事件加入激活隊列中去,此時,EV_READ表示該事件激活是由於可讀。

可見ev_res的取值內容同ev_events一致。

void
event_active(struct event *ev, int res, short ncalls)
{
	ev->ev_res = res;
	event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
}
當處理該事件的時候,ev_res傳遞給用戶回調函數。

while (ncalls) {
    ncalls--;
    ev->ev_ncalls = ncalls;
    (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
    if (base->event_break)
        return;
}
插一句:上述可以看到如果event_break爲真,立即返回,即使激活事件隊列中還有激活事件,也不在進行處理了。



發佈了122 篇原創文章 · 獲贊 42 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章