就如libevent官網上所寫的「libevent - an event notification library」,libevent就是一個基於事件通知機制的庫,能夠看出event是整個庫的核心。event就是Reactor框架中的事件處理程序組件(event_handler),它提供了函數接口,供Reactor在事件發生時調用,以執行相應的事件處理,一般它會綁定一個有效的句柄。框架
event結構體定義在<event2/event_struct.h>中:socket
1 struct event { 2 TAILQ_ENTRY(event) ev_active_next; 3 TAILQ_ENTRY(event) ev_next; 4 /* for managing timeouts */ 5 union { 6 TAILQ_ENTRY(event) ev_next_with_common_timeout; 7 int min_heap_idx; 8 } ev_timeout_pos; 9 evutil_socket_t ev_fd; 10 11 struct event_base *ev_base; 12 13 union { // I/O事件和信號事件不能同時設置 14 /* used for io events */ 15 struct { 16 TAILQ_ENTRY(event) ev_io_next; 17 struct timeval ev_timeout; 18 } ev_io; 19 20 /* used by signal events */ 21 struct { 22 TAILQ_ENTRY(event) ev_signal_next; 23 short ev_ncalls; 24 /* Allows deletes in callback */ 25 short *ev_pncalls; 26 } ev_signal; 27 } _ev; 28 29 short ev_events; 30 short ev_res; /* result passed to event callback */ 31 short ev_flags; 32 ev_uint8_t ev_pri; /* smaller numbers are higher priority */ 33 ev_uint8_t ev_closure; 34 struct timeval ev_timeout; 35 36 /* allows us to adopt for different types of events */ 37 void (*ev_callback)(evutil_socket_t, short, void *arg); 38 void *ev_arg; 39 };
在原文檔中,做者對event結構體作了詳細的解釋(英文):ide
/** * @struct event * * Structure to represent a single event. * * An event can have some underlying condition it represents: a socket * becoming readable or writeable (or both), or a signal becoming raised. * (An event that represents no underlying condition is still useful: you * can use one to implement a timer, or to communicate between threads.) * * Generally, you can create events with event_new(), then make them * pending with event_add(). As your event_base runs, it will run the * callbacks of an events whose conditions are triggered. When you * longer want the event, free it with event_free(). * * In more depth: * * An event may be "pending" (one whose condition we are watching), * "active" (one whose condition has triggered and whose callback is about * to run), neither, or both. Events come into existence via * event_assign() or event_new(), and are then neither active nor pending. * * To make an event pending, pass it to event_add(). When doing so, you * can also set a timeout for the event. * * Events become active during an event_base_loop() call when either their * condition has triggered, or when their timeout has elapsed. You can * also activate an event manually using event_active(). The even_base * loop will run the callbacks of active events; after it has done so, it * marks them as no longer active. * * You can make an event non-pending by passing it to event_del(). This * also makes the event non-active. * * Events can be "persistent" or "non-persistent". A non-persistent event * becomes non-pending as soon as it is triggered: thus, it only runs at * most once per call to event_add(). A persistent event remains pending * even when it becomes active: you'll need to event_del() it manually in * order to make it non-pending. When a persistent event with a timeout * becomes active, its timeout is reset: this means you can use persistent * events to implement periodic timeouts. * * This should be treated as an opaque structure; you should never read or * write any of its fields directly. For backward compatibility with old * code, it is defined in the event2/event_struct.h header; including this * header may make your code incompatible with other versions of Libevent. * * @see event_new(), event_free(), event_assign(), event_get_assignment(), * event_add(), event_del(), event_active(), event_pending(), * event_get_fd(), event_get_base(), event_get_events(), * event_get_callback(), event_get_callback_arg(), * event_priority_set() */
注意上述中提到的pending和active的區別。pending表示的是監聽事件的列表,而active表示的是已激活事件的列表。函數
下面簡單解釋一下結構體中重要字段的含義:
1)ev_events:說明要監聽的事件類型(event支持I/O、超時和信號3種事件類型,),它的值可由如下字段位與而成:oop
1 /** 2 * @name event flags 3 * 4 * Flags to pass to event_new(), event_assign(), event_pending(), and 5 * anything else with an argument of the form "short events" 6 */ 7 /**@{*/ 8 /** Indicates that a timeout has occurred. It's not necessary to pass 9 * this flag to event_for new()/event_assign() to get a timeout. */ 10 #define EV_TIMEOUT 0x01 11 /** Wait for a socket or FD to become readable */ 12 #define EV_READ 0x02 13 /** Wait for a socket or FD to become writeable */ 14 #define EV_WRITE 0x04 15 /** Wait for a POSIX signal to be raised*/ 16 #define EV_SIGNAL 0x08 17 /** 18 * Persistent event: won't get removed automatically when activated. 19 * 20 * When a persistent event with a timeout becomes activated, its timeout 21 * is reset to 0. 22 */ 23 #define EV_PERSIST 0x10 24 /** Select edge-triggered behavior, if supported by the backend. */ 25 #define EV_ET 0x20 26 /**@}*/
2)ev_next、ev_active_next、ev_next_with_common_timeout、ev_io_next和ev_signal_next都是雙向鏈表節點指針。它們是libevent對不一樣事件類型和在不一樣的時期,對事件的管理時使用到的字段。ui
3)min_heap_idx或ev_next_with_common_timeout指明超時事件在小根堆中的索引或在timeout list中的位置。this
4)ev_base該事件所屬的反應堆實例,這是一個event_base結構體。spa
5)ev_fd,對於I/O事件,是綁定的文件描述符;對於signal事件,是綁定的信號。.net
6)eb_flags:libevent用於標記event信息的字段,代表其當前的狀態,可能的值有:debug
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已被初始化
7)ev_callback,event的回調函數,被ev_base調用,執行事件處理程序,這是一個函數指針,原型爲:
void (*ev_callback)(int fd, short events, void *arg)
其中參數fd對應於ev_fd;events對應於ev_events;arg對應於ev_arg;
8)ev_arg:void*,代表能夠是任意類型的數據,在設置event時指定;
9)ev_ncalls:事件就緒執行時,調用ev_callback的次數,一般爲1;
10)ev_pncalls:指針,一般指向ev_ncalls或者爲NULL;
11)ev_res:記錄了當前激活事件的類型;
libevent對event的管理以下圖所示:
每次當有事件event轉變爲就緒狀態時,libevent就會把它移入到active event list[priority]中,其中priority是event的優先級;接着libevent會根據本身的調度策略選擇就緒事件,調用其cb_callback() 函數執行事件處理,並根據就緒的句柄和事件類型填充cb_callback函數的參數。
在libevent,有幾個函數能夠用於設置事件的屬性:
1. event_set
用於設置event屬性的event_set函數其實是調用了event_assign。
1 void 2 event_set(struct event *ev, evutil_socket_t fd, short events, 3 void (*callback)(evutil_socket_t, short, void *), void *arg) 4 { 5 int r; 6 r = event_assign(ev, current_base, fd, events, callback, arg); 7 EVUTIL_ASSERT(r == 0); 8 }
而event_assign函數的定義爲:
1 int 2 event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg) 3 { 4 if (!base) 5 base = current_base; 6 7 _event_debug_assert_not_added(ev); 8 9 ev->ev_base = base; 10 11 ev->ev_callback = callback; 12 ev->ev_arg = arg; 13 ev->ev_fd = fd; 14 ev->ev_events = events; 15 ev->ev_res = 0; 16 ev->ev_flags = EVLIST_INIT; 17 ev->ev_ncalls = 0; 18 ev->ev_pncalls = NULL; 19 20 if (events & EV_SIGNAL) { 21 if ((events & (EV_READ|EV_WRITE)) != 0) { 22 event_warnx("%s: EV_SIGNAL is not compatible with " 23 "EV_READ or EV_WRITE", __func__); 24 return -1; 25 } 26 ev->ev_closure = EV_CLOSURE_SIGNAL; 27 } else { 28 if (events & EV_PERSIST) { 29 evutil_timerclear(&ev->ev_io_timeout); 30 ev->ev_closure = EV_CLOSURE_PERSIST; 31 } else { 32 ev->ev_closure = EV_CLOSURE_NONE; 33 } 34 } 35 36 min_heap_elem_init(ev); 37 38 if (base != NULL) { 39 /* by default, we put new events into the middle priority */ 40 ev->ev_pri = base->nactivequeues / 2; 41 } 42 43 _event_debug_note_setup(ev); 44 45 return 0; 46 }
其中,參數爲:
另外,咱們也能夠在建立新事件的時候設定事件屬性,具體函數是event_new。而event_new實際也是調用了event_assign來實現的,不一樣的是event_new須要先給事件分配空間:
1 struct event * 2 event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg) 3 { 4 struct event *ev; 5 ev = mm_malloc(sizeof(struct event)); 6 if (ev == NULL) 7 return (NULL); 8 if (event_assign(ev, base, fd, events, cb, arg) < 0) { 9 mm_free(ev); 10 return (NULL); 11 } 12 13 return (ev); 14 }
2. event_base_set
在默認狀況下,事件event會被註冊到一個全局event_base指針current_base。使用該函數能夠指定不一樣的event_base。若是一個進程中存在多個libevent實例,必需要調用該函數爲event設置不一樣的event_base。
該函數的定義以下:
1 int 2 event_base_set(struct event_base *base, struct event *ev) 3 { 4 /* Only innocent events may be assigned to a different base */ 5 if (ev->ev_flags != EVLIST_INIT) 6 return (-1); 7 8 _event_debug_assert_is_setup(ev); 9 10 ev->ev_base = base; 11 ev->ev_pri = base->nactivequeues/2; 12 13 return (0); 14 }
3. event_priority_set
在默認狀況下,全部的event的優先級都被設定爲 active event list 長度的一半(nactivequeues / 2)。該函數可用於設定event的優先級。優先級的數值越小,表示優先級越高。另外,函數event_base_priority_init可用於設定優先級的最大值。
event_priority_set的函數定義以下:
1 /* 2 * Set's the priority of an event - if an event is already scheduled 3 * changing the priority is going to fail. 4 */ 5 6 int 7 event_priority_set(struct event *ev, int pri) 8 { 9 _event_debug_assert_is_setup(ev); 10 11 if (ev->ev_flags & EVLIST_ACTIVE) 12 return (-1); 13 if (pri < 0 || pri >= ev->ev_base->nactivequeues) 14 return (-1); 15 16 ev->ev_pri = pri; 17 18 return (0); 19 }
1. event_new
建立事件(涉及內存分配)。
1. event_add
添加事件到event_base。
2. event_del
將事件從監聽列表中移除。
3. event_free
釋放由event_new建立的事件(內存)。從其定義可看出其與event_del的區別:
1 void 2 event_free(struct event *ev) 3 { 4 _event_debug_assert_is_setup(ev); 5 6 /* make sure that this event won't be coming back to haunt us. */ 7 event_del(ev); 8 _event_debug_note_teardown(ev); 9 mm_free(ev); 10 11 }
3. event_callback_fn
事件的回調函數,用於執行具體的I/O操做。其定義以下:
1 /** 2 A callback function for an event. 3 4 It receives three arguments: 5 6 @param fd An fd or signal 7 @param events One or more EV_* flags 8 @param arg A user-supplied argument. 9 10 @see event_new() 11 */ 12 typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
爲了方便對超時和信號事件的處理,libevent特別爲它們定義了接口函數(實際是對通用函數的封裝)。
超時事件:
1 /** 2 @name evtimer_* macros 3 4 Aliases for working with one-shot timer events */ 5 /**@{*/ 6 #define evtimer_assign(ev, b, cb, arg) \ 7 event_assign((ev), (b), -1, 0, (cb), (arg)) 8 #define evtimer_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg)) 9 #define evtimer_add(ev, tv) event_add((ev), (tv)) 10 #define evtimer_del(ev) event_del(ev) 11 #define evtimer_pending(ev, tv) event_pending((ev), EV_TIMEOUT, (tv)) 12 #define evtimer_initialized(ev) event_initialized(ev) 13 /**@}*/
信號事件:
1 /** 2 @name evsignal_* macros 3 4 Aliases for working with signal events 5 */ 6 /**@{*/ 7 #define evsignal_add(ev, tv) event_add((ev), (tv)) 8 #define evsignal_assign(ev, b, x, cb, arg) \ 9 event_assign((ev), (b), (x), EV_SIGNAL|EV_PERSIST, cb, (arg)) 10 #define evsignal_new(b, x, cb, arg) \ 11 event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg)) 12 #define evsignal_del(ev) event_del(ev) 13 #define evsignal_pending(ev, tv) event_pending((ev), EV_SIGNAL, (tv)) 14 #define evsignal_initialized(ev) event_initialized(ev) 15 /**@}*/