(五)struct event結構體

前言

之前說到過libevent是基於事件驅動模型的網絡庫,其中的事件,就是event,它的確算是libevent中最核心的部分,而上一節說到的event_base其實算是驅動部分,負責事件的各種處理。它們之間的關係是,一個event_base對應多個event
下面主要講解的是struct event結構體,位於event.h

struct event

struct event {
    /* 尾隊列節點指針 用於保存所有註冊了的I/O以及signal事件 以及激活的事件(其實libevent中的尾隊列本質上就是一個雙向鏈表)*/
    TAILQ_ENTRY (event) ev_next;    //已註冊I/O事件鏈表
    TAILQ_ENTRY (event) ev_active_next; //所有激活了的事件鏈表,通過遍歷該鏈表進行調度
    TAILQ_ENTRY (event) ev_signal_next; //已註冊signal事件鏈表

    unsigned int min_heap_idx;  /* for managing timeouts */

    struct event_base *ev_base; //該事件所屬的反應堆實例

    int ev_fd;  //對於I/O事件,是綁定的文件描述符。對於signal事件,是綁定的信號
    short ev_events;    /* 事件的類型 */
    short ev_ncalls;    //事件就緒執行時,調用ev_callback的次數
    short *ev_pncalls;  /* Allows deletes in callback */

    struct timeval ev_timeout; //定時的時長

    int ev_pri; //優先級 smaller numbers are higher priority

    /* event的回調函數,被ev_base調用
     * int參數代表ev_fd
     * short參數代表事件的類型,即ev_events
     * void *arg對應ev_arg
     */

    void (*ev_callback)(int, short, void *arg);
    void *ev_arg;

    int ev_res; //當前激活事件的類型 /* result passed to event callback */
    int ev_flags; //表明當前event的狀態
};

額外注意

有以下幾點進行補充說明:
1. TAILQ_ENTRY()是一個宏,原型如下:

#define TAILQ_ENTRY(type)                       \
struct {                                \
     struct type *tqe_next; /* next element */          \
     struct type **tqe_prev;    /* address of previous next element */  \
 }

如你所見,它其實是一個尾隊列結點。它的第一個成員tqe_next指向下一個元素,第二個成員tqe_prev是前一個元素的下個元素的地址。這樣做的好處是,刪除元素時不必遍歷整個鏈表,同時也支持方向遍歷。具體的操作等後面遇到了再講。
2.
事件類型(short ev_events)有如下4種:

/* 定時事件 */
#define EV_TIMEOUT  0x01

/* I/O事件 */
#define EV_READ     0x02
#define EV_WRITE    0x04

/* 信號事件 */
#define EV_SIGNAL   0x08

/* 輔助選項:表明是永久(持續的)事件 */
#define EV_PERSIST  0x10    /* Persistant event */

這些事件可以進行|操作,即一個事件可以是多種類型的,不過signal類型不能和I/O類型同爲同一事件。
3. event的狀態(int ev_flags)有如下幾種:

#define EVLIST_TIMEOUT 0x01 // event在time堆中
#define EVLIST_INSERTED 0x02 // event在已註冊事件鏈表中
#define EVLIST_SIGNAL 0x04 // 未見其他源文件使用
#define EVLIST_ACTIVE 0x08 // event在激活鏈表中
#define EVLIST_INTERNAL 0x10 // 內部使用標記
#define EVLIST_INIT 0x80 // event 已被初始化

4. 通過查看該結構體的成員,我們不難發現,libevent將事件分爲了I/O事件信號事件定時事件這幾類,並且管理註冊事件的時候分了不同的鏈表來管理,已經激活等待調度的事件也有一個專門的鏈表來管理。
5. 還有一個優先級的概念,前面我們在介紹event_base結構體時,有個成員是activequeues,它專門用來按優先級管理已經激活(就緒)的事件。於是,每當有event被激活時,libevent就會把它移入activequeues[event->ev_pri]中。
6. 接着便是回調函數,event負責保管回調函數指針,真正來調用的是事件主循環中的event_process_active函數。

小結

OK,我們當前看了libevent中最主要的兩個結構體:struct eventstruct event_base,瞭解到event將事件分類管理,裏面存放了重要的回調函數指針並且知道了它和event_base的關係(多對一)。下面我們可以忽略信號和定時部分,看一看event_baseevent之間是如何協調的,這對我們理解eventevent_base很有好處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章