struct event

對事件處理流程有了高層的認識後,本節將詳細介紹libevent的核心結構event,以及libevent對event的管理。

1 libevent的核心-event

      Libevent是基於事件驅動(event-driven)的,從名字也可以看到event是整個庫的核心。event就是Reactor框架中的事件處理程序組件;它提供了函數接口,供Reactor在事件發生時調用,以執行相應的事件處理,通常它會綁定一個有效的句柄。
首先給出event結構體的聲明,它位於event.h文件中:

  1. struct event {  
  2.  TAILQ_ENTRY (event) ev_next;  
  3.  TAILQ_ENTRY (event) ev_active_next;  
  4.  TAILQ_ENTRY (event) ev_signal_next;  
  5.  unsigned int min_heap_idx; /* for managing timeouts */  
  6.  struct event_base *ev_base;  
  7.  int ev_fd;  
  8.  short ev_events;  
  9.  short ev_ncalls;  
  10.  short *ev_pncalls; /* Allows deletes in callback */  
  11.  struct timeval ev_timeout;  
  12.  int ev_pri;  /* smaller numbers are higher priority */  
  13.  void (*ev_callback)(intshortvoid *arg);  
  14.  void *ev_arg;  
  15.  int ev_res;  /* result passed to event callback */  
  16.  int ev_flags;  
  17. };  

下面簡單解釋一下結構體中各字段的含義。
1)ev_events:event關注的事件類型,它可以是以下3種類型:
I/O事件: EV_WRITE和EV_READ
定時事件:EV_TIMEOUT
信號:    EV_SIGNAL
輔助選項:EV_PERSIST,表明是一個永久事件
Libevent中的定義爲:
  1. #define EV_TIMEOUT 0x01  
  2. #define EV_READ  0x02  
  3. #define EV_WRITE 0x04  
  4. #define EV_SIGNAL 0x08  
  5. #define EV_PERSIST 0x10 /* Persistant event */  

可以看出事件類型可以使用“|”運算符進行組合,需要說明的是,信號和I/O事件不能同時設置;
還可以看出libevent使用event結構體將這3種事件的處理統一起來;
2)ev_next,ev_active_next和ev_signal_next都是雙向鏈表節點指針;它們是libevent對不同事件類型和在不同的時期,對事件的管理時使用到的字段。
libevent使用雙向鏈表保存所有註冊的I/O和Signal事件,ev_next就是該I/O事件在鏈表中的位置;稱此鏈表爲“已註冊事件鏈表”;
同樣ev_signal_next就是signal事件在signal事件鏈表中的位置;
ev_active_next:libevent將所有的激活事件放入到鏈表active list中,然後遍歷active list執行調度,ev_active_next就指明瞭event在active list中的位置;
2)min_heap_idx和ev_timeout,如果是timeout事件,它們是event在小根堆中的索引和超時值,libevent使用小根堆來管理定時事件,這將在後面定時事件處理時專門講解
3)ev_base該事件所屬的反應堆實例,這是一個event_base結構體,下一節將會詳細講解;
4)ev_fd,對於I/O事件,是綁定的文件描述符;對於signal事件,是綁定的信號;
5)ev_callback,event的回調函數,被ev_base調用,執行事件處理程序,這是一個函數指針,原型爲:
void (*ev_callback)(int fd, short events, void *arg)
其中參數fd對應於ev_fd;events對應於ev_events;arg對應於ev_arg;
6)ev_arg:void*,表明可以是任意類型的數據,在設置event時指定;
7)eb_flags:libevent用於標記event信息的字段,表明其當前的狀態,可能的值有:
  1. #define EVLIST_TIMEOUT 0x01 // event在time堆中  
  2. #define EVLIST_INSERTED 0x02 // event在已註冊事件鏈表中  
  3. #define EVLIST_SIGNAL 0x04 // 未見使用  
  4. #define EVLIST_ACTIVE 0x08 // event在激活鏈表中  
  5. #define EVLIST_INTERNAL 0x10 // 內部使用標記  
  6. #define EVLIST_INIT     0x80 // event已被初始化  

8)ev_ncalls:事件就緒執行時,調用ev_callback的次數,通常爲1;
9)ev_pncalls:指針,通常指向ev_ncalls或者爲NULL;
10)ev_res:記錄了當前激活事件的類型;

 

2 libevent對event的管理
     

       從event結構體中的3個鏈表節點指針和一個堆索引出發,大體上也能窺出libevent對event的管理方法了,可以參見下面的示意圖:
 event management

      每次當有事件event轉變爲就緒狀態時,libevent就會把它移入到active event list[priority]中,其中priority是event的優先級;
接着libevent會根據自己的調度策略選擇就緒事件,調用其cb_callback()函數執行事件處理;並根據就緒的句柄和事件類型填充cb_callback函數的參數。

3 事件設置的接口函數

     要向libevent添加一個事件,需要首先設置event對象,這通過調用libevent提供的函數有:event_set(), event_base_set(), event_priority_set()來完成;下面分別進行講解。

void event_set(struct event *ev, int fd, short events,
   void (*callback)(int, short, void *), void *arg)
1.設置事件ev綁定的文件描述符或者信號,對於定時事件,設爲-1即可;
2.設置事件類型,比如EV_READ|EV_PERSIST, EV_WRITE, EV_SIGNAL等;
3.設置事件的回調函數以及參數arg;
4.初始化其它字段,比如缺省的event_base和優先級;
int event_base_set(struct event_base *base, struct event *ev)
設置event ev將要註冊到的event_base;
libevent有一個全局event_base指針current_base,默認情況下事件ev將被註冊到current_base上,使用該函數可以指定不同的event_base;
如果一個進程中存在多個libevent實例,則必須要調用該函數爲event設置不同的event_base;

int event_priority_set(struct event *ev, int pri)
設置event ev的優先級,沒什麼可說的,注意的一點就是:當ev正處於就緒狀態時,不能設置,返回-1。

4 小結

      本節講述了libevent的核心event結構,以及libevent支持的事件類型和libevent對event的管理模型;接下來將會描述libevent的事件處理框架,以及其中使用的重要的結構體event_base;

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