libevent之event_base
event_base是libevent的事务处理框架,负责事件注册、删除等,属于Reactor模式中的Reactor。
event_base结构体
event_base结构体定义于<event_internal.h>中:
1 struct event_base { 2 /** Function pointers and other data to describe this event_base's 3 * backend. */ 4 const struct eventop *evsel; 5 /** Pointer to backend-specific data. */ 6 void *evbase; 7 8 /** List of changes to tell backend about at next dispatch. Only used 9 * by the O(1) backends. */ 10 struct event_changelist changelist; 11 12 /** Function pointers used to describe the backend that this event_base 13 * uses for signals */ 14 const struct eventop *evsigsel; 15 /** Data to implement the common signal handelr code. */ 16 struct evsig_info sig; 17 18 /** Number of virtual events */ 19 int virtual_event_count; 20 /** Number of total events added to this event_base */ 21 int event_count; 22 /** Number of total events active in this event_base */ 23 int event_count_active; 24 25 /** Set if we should terminate the loop once we're done processing 26 * events. */ 27 int event_gotterm; 28 /** Set if we should terminate the loop immediately */ 29 int event_break; 30 /** Set if we should start a new instance of the loop immediately. */ 31 int event_continue; 32 33 /** The currently running priority of events */ 34 int event_running_priority; 35 36 /** Set if we're running the event_base_loop function, to prevent 37 * reentrant invocation. */ 38 int running_loop; 39 40 /* Active event management. */ 41 /** An array of nactivequeues queues for active events (ones that 42 * have triggered, and whose callbacks need to be called). Low 43 * priority numbers are more important, and stall higher ones. 44 */ 45 struct event_list *activequeues; 46 /** The length of the activequeues array */ 47 int nactivequeues; 48 49 /* common timeout logic */ 50 51 /** An array of common_timeout_list* for all of the common timeout 52 * values we know. */ 53 struct common_timeout_list **common_timeout_queues; 54 /** The number of entries used in common_timeout_queues */ 55 int n_common_timeouts; 56 /** The total size of common_timeout_queues. */ 57 int n_common_timeouts_allocated; 58 59 /** List of defered_cb that are active. We run these after the active 60 * events. */ 61 struct deferred_cb_queue defer_queue; 62 63 /** Mapping from file descriptors to enabled (added) events */ 64 struct event_io_map io; 65 66 /** Mapping from signal numbers to enabled (added) events. */ 67 struct event_signal_map sigmap; 68 69 /** All events that have been enabled (added) in this event_base */ 70 struct event_list eventqueue; 71 72 /** Stored timeval; used to detect when time is running backwards. */ 73 struct timeval event_tv; 74 75 /** Priority queue of events with timeouts. */ 76 struct min_heap timeheap; 77 78 /** Stored timeval: used to avoid calling gettimeofday/clock_gettime 79 * too often. */ 80 struct timeval tv_cache; 81 82 #if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) 83 /** Difference between internal time (maybe from clock_gettime) and 84 * gettimeofday. */ 85 struct timeval tv_clock_diff; 86 /** Second in which we last updated tv_clock_diff, in monotonic time. */ 87 time_t last_updated_clock_diff; 88 #endif 89 90 #ifndef _EVENT_DISABLE_THREAD_SUPPORT 91 /* threading support */ 92 /** The thread currently running the event_loop for this base */ 93 unsigned long th_owner_id; 94 /** A lock to prevent conflicting accesses to this event_base */ 95 void *th_base_lock; 96 /** The event whose callback is executing right now */ 97 struct event *current_event; 98 /** A condition that gets signalled when we're done processing an 99 * event with waiters on it. */ 100 void *current_event_cond; 101 /** Number of threads blocking on current_event_cond. */ 102 int current_event_waiters; 103 #endif 104 105 #ifdef WIN32 106 /** IOCP support structure, if IOCP is enabled. */ 107 struct event_iocp_port *iocp; 108 #endif 109 110 /** Flags that this base was configured with */ 111 enum event_base_config_flag flags; 112 113 /* Notify main thread to wake up break, etc. */ 114 /** True if the base already has a pending notify, and we don't need 115 * to add any more. */ 116 int is_notify_pending; 117 /** A socketpair used by some th_notify functions to wake up the main 118 * thread. */ 119 evutil_socket_t th_notify_fd[2]; 120 /** An event used by some th_notify functions to wake up the main 121 * thread. */ 122 struct event th_notify; 123 /** A function used to wake up the main thread from another thread. */ 124 int (*th_notify_fn)(struct event_base *base); 125 };
其中值得注意的是evsel和evbase。evsel指向了全局变量
static const struct eventop *eventops[]
中的一个元素,而evbase则实际执行多路复用机制的实例化。
如果我们看函数event_base_new_with_config的定义就会比较清晰evsel和evbase之间的关系了:
// <event.c>
1 struct event_base * 2 event_base_new_with_config(const struct event_config *cfg) 3 { 4 ...... 5 6 for (i = 0; eventops[i] && !base->evbase; i++) { 7 if (cfg != NULL) { 8 /* determine if this backend should be avoided */ 9 if (event_config_is_avoided_method(cfg, 10 eventops[i]->name)) 11 continue; 12 if ((eventops[i]->features & cfg->require_features) 13 != cfg->require_features) 14 continue; 15 } 16 17 /* also obey the environment variables */ 18 if (should_check_environment && 19 event_is_method_disabled(eventops[i]->name)) 20 continue; 21 22 base->evsel = eventops[i]; 23 24 base->evbase = base->evsel->init(base); 25 } 26 27 ...... 28 }
event_base创建及初始化
创建event_base对象即是创建一个libevent实例。具体的创建函数是event_base_new:
1 struct event_base * 2 event_base_new(void) 3 { 4 struct event_base *base = NULL; 5 struct event_config *cfg = event_config_new(); 6 if (cfg) { 7 base = event_base_new_with_config(cfg); 8 event_config_free(cfg); 9 } 10 return base; 11 }
由上边程序知道,event_base创建的关键所在是event_base_new_with_config函数,而此函数又通过调用多路调用机制的初始化函数来初始化event_base实例:
1 // <event.c> 2 struct event_base * 3 event_base_new_with_config(const struct event_config *cfg) 4 { 5 ...... 6 7 for (i = 0; eventops[i] && !base->evbase; i++) { 8 if (cfg != NULL) { 9 /* determine if this backend should be avoided */ 10 if (event_config_is_avoided_method(cfg, 11 eventops[i]->name)) 12 continue; 13 if ((eventops[i]->features & cfg->require_features) 14 != cfg->require_features) 15 continue; 16 } 17 18 /* also obey the environment variables */ 19 if (should_check_environment && 20 event_is_method_disabled(eventops[i]->name)) 21 continue; 22 23 base->evsel = eventops[i]; 24 25 base->evbase = base->evsel->init(base); 26 } 27 28 ...... 29 }
以epoll为例,其对event_base实例的初始化函数为:
1 static void * 2 epoll_init(struct event_base *base) 3 { 4 int epfd; 5 struct epollop *epollop; 6 7 /* Initialize the kernel queue. (The size field is ignored since 8 * 2.6.8.) */ 9 if ((epfd = epoll_create(32000)) == -1) { 10 if (errno != ENOSYS) 11 event_warn("epoll_create"); 12 return (NULL); 13 } 14 15 evutil_make_socket_closeonexec(epfd); 16 17 if (!(epollop = mm_calloc(1, sizeof(struct epollop)))) { 18 close(epfd); 19 return (NULL); 20 } 21 22 epollop->epfd = epfd; 23 24 /* Initialize fields */ 25 epollop->events = mm_calloc(INITIAL_NEVENT, sizeof(struct epoll_event)); 26 if (epollop->events == NULL) { 27 mm_free(epollop); 28 close(epfd); 29 return (NULL); 30 } 31 epollop->nevents = INITIAL_NEVENT; 32 33 if ((base->flags & EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST) != 0 || 34 ((base->flags & EVENT_BASE_FLAG_IGNORE_ENV) == 0 && 35 evutil_getenv("EVENT_EPOLL_USE_CHANGELIST") != NULL)) 36 base->evsel = &epollops_changelist; 37 38 evsig_init(base); 39 40 return (epollop); 41 } 42 43 struct epollop { 44 struct epoll_event *events; // 并发服务器--02(基于I/O复用——运用epoll技术) 45 int nevents; 46 int epfd; 47 };
接口函数
事件相关的常用接口函数
1. event_new
创建事件(涉及内存分配)。
1. event_add
添加事件到event_base。
2. event_del
将事件从监听列表(pending list)中移除。
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 /**@}*/
事件处理主循环
有待添加
参考资料