分析libevent的源代码,我的想法的是先分析各种结构体,struct event_base、struct event,然后是event_base_new函数、event_new函数、event_add函数,最后分析event_base_dispatch函数。
一、各种结构体
1、event_base
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 /** Maximum number of virtual events active */ 21 int virtual_event_count_max; 22 /** Number of total events added to this event_base */ 23 int event_count; 24 /** Maximum number of total events added to this event_base */ 25 int event_count_max; 26 /** Number of total events active in this event_base */ 27 int event_count_active; 28 /** Maximum number of total events active in this event_base */ 29 int event_count_active_max; 30 31 /** Set if we should terminate the loop once we're done processing 32 * events. */ 33 int event_gotterm; 34 /** Set if we should terminate the loop immediately */ 35 int event_break; 36 /** Set if we should start a new instance of the loop immediately. */ 37 int event_continue; 38 39 /** The currently running priority of events */ 40 int event_running_priority; 41 42 /** Set if we're running the event_base_loop function, to prevent 43 * reentrant invocation. */ 44 int running_loop; 45 46 /** Set to the number of deferred_cbs we've made 'active' in the 47 * loop. This is a hack to prevent starvation; it would be smarter 48 * to just use event_config_set_max_dispatch_interval's max_callbacks 49 * feature */ 50 int n_deferreds_queued; 51 52 /* Active event management. */ 53 /** An array of nactivequeues queues for active event_callbacks (ones 54 * that have triggered, and whose callbacks need to be called). Low 55 * priority numbers are more important, and stall higher ones. 56 */ 57 struct evcallback_list *activequeues; 58 /** The length of the activequeues array */ 59 int nactivequeues; 60 /** A list of event_callbacks that should become active the next time 61 * we process events, but not this time. */ 62 struct evcallback_list active_later_queue; 63 64 /* common timeout logic */ 65 66 /** An array of common_timeout_list* for all of the common timeout 67 * values we know. */ 68 struct common_timeout_list **common_timeout_queues; 69 /** The number of entries used in common_timeout_queues */ 70 int n_common_timeouts; 71 /** The total size of common_timeout_queues. */ 72 int n_common_timeouts_allocated; 73 74 /** Mapping from file descriptors to enabled (added) events */ 75 struct event_io_map io; 76 77 /** Mapping from signal numbers to enabled (added) events. */ 78 struct event_signal_map sigmap; 79 80 /** Priority queue of events with timeouts. */ 81 struct min_heap timeheap; 82 83 /** Stored timeval: used to avoid calling gettimeofday/clock_gettime 84 * too often. */ 85 struct timeval tv_cache; 86 87 struct evutil_monotonic_timer monotonic_timer; 88 89 /** Difference between internal time (maybe from clock_gettime) and 90 * gettimeofday. */ 91 struct timeval tv_clock_diff; 92 /** Second in which we last updated tv_clock_diff, in monotonic time. */ 93 time_t last_updated_clock_diff; 94 95 #ifndef EVENT__DISABLE_THREAD_SUPPORT 96 /* threading support */ 97 /** The thread currently running the event_loop for this base */ 98 unsigned long th_owner_id; 99 /** A lock to prevent conflicting accesses to this event_base */ 100 void *th_base_lock; 101 /** A condition that gets signalled when we're done processing an 102 * event with waiters on it. */ 103 void *current_event_cond; 104 /** Number of threads blocking on current_event_cond. */ 105 int current_event_waiters; 106 #endif 107 /** The event whose callback is executing right now */ 108 struct event_callback *current_event; 109 110 #ifdef _WIN32 111 /** IOCP support structure, if IOCP is enabled. */ 112 struct event_iocp_port *iocp; 113 #endif 114 115 /** Flags that this base was configured with */ 116 enum event_base_config_flag flags; 117 118 struct timeval max_dispatch_time; 119 int max_dispatch_callbacks; 120 int limit_callbacks_after_prio; 121 122 /* Notify main thread to wake up break, etc. */ 123 /** True if the base already has a pending notify, and we don't need 124 * to add any more. */ 125 int is_notify_pending; 126 /** A socketpair used by some th_notify functions to wake up the main 127 * thread. */ 128 evutil_socket_t th_notify_fd[2]; 129 /** An event used by some th_notify functions to wake up the main 130 * thread. */ 131 struct event th_notify; 132 /** A function used to wake up the main thread from another thread. */ 133 int (*th_notify_fn)(struct event_base *base); 134 135 /** Saved seed for weak random number generator. Some backends use 136 * this to produce fairness among sockets. Protected by th_base_lock. */ 137 struct evutil_weakrand_state weakrand_seed; 138 139 /** List of event_onces that have not yet fired. */ 140 LIST_HEAD(once_event_list, event_once) once_events; 141 142 };
struct event_base结构体在event-internal.h文件中定义。
二、初始化函数
1、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 }
(1)调用event_config_new函数分配一个struct event_config结构体。
(2)如果分配成功,就调用event_base_new_with_config(cfg)分配一个struct event_base对象指针,然后将该指针返回。
总结:所以event_base_new还是调用了event_base_new_with_config函数。所以下面接着来看event_base_new_with_config函数。
2、event_base_new_with_config函数
1 struct event_base * 2 event_base_new_with_config(const struct event_config *cfg) 3 { 4 int i; 5 struct event_base *base; 6 int should_check_environment; 7 8 #ifndef EVENT__DISABLE_DEBUG_MODE 9 event_debug_mode_too_late = 1; 10 #endif 11 12 if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) { 13 event_warn("%s: calloc", __func__); 14 return NULL; 15 } 16 17 if (cfg) 18 base->flags = cfg->flags; 19 20 should_check_environment = 21 !(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV)); 22 23 { 24 struct timeval tmp; 25 int precise_time = 26 cfg && (cfg->flags & EVENT_BASE_FLAG_PRECISE_TIMER); 27 int flags; 28 if (should_check_environment && !precise_time) { 29 precise_time = evutil_getenv_("EVENT_PRECISE_TIMER") != NULL; 30 base->flags |= EVENT_BASE_FLAG_PRECISE_TIMER; 31 } 32 flags = precise_time ? EV_MONOT_PRECISE : 0; 33 evutil_configure_monotonic_time_(&base->monotonic_timer, flags); 34 35 gettime(base, &tmp); 36 } 37 38 min_heap_ctor_(&base->timeheap); 39 40 base->sig.ev_signal_pair[0] = -1; 41 base->sig.ev_signal_pair[1] = -1; 42 base->th_notify_fd[0] = -1; 43 base->th_notify_fd[1] = -1; 44 45 TAILQ_INIT(&base->active_later_queue); 46 47 evmap_io_initmap_(&base->io); 48 evmap_signal_initmap_(&base->sigmap); 49 event_changelist_init_(&base->changelist); 50 51 base->evbase = NULL; 52 53 if (cfg) { 54 memcpy(&base->max_dispatch_time, 55 &cfg->max_dispatch_interval, sizeof(struct timeval)); 56 base->limit_callbacks_after_prio = 57 cfg->limit_callbacks_after_prio; 58 } else { 59 base->max_dispatch_time.tv_sec = -1; 60 base->limit_callbacks_after_prio = 1; 61 } 62 if (cfg && cfg->max_dispatch_callbacks >= 0) { 63 base->max_dispatch_callbacks = cfg->max_dispatch_callbacks; 64 } else { 65 base->max_dispatch_callbacks = INT_MAX; 66 } 67 if (base->max_dispatch_callbacks == INT_MAX && 68 base->max_dispatch_time.tv_sec == -1) 69 base->limit_callbacks_after_prio = INT_MAX; 70 71 for (i = 0; eventops[i] && !base->evbase; i++) { 72 if (cfg != NULL) { 73 /* determine if this backend should be avoided */ 74 if (event_config_is_avoided_method(cfg, 75 eventops[i]->name)) 76 continue; 77 if ((eventops[i]->features & cfg->require_features) 78 != cfg->require_features) 79 continue; 80 } 81 82 /* also obey the environment variables */ 83 if (should_check_environment && 84 event_is_method_disabled(eventops[i]->name)) 85 continue; 86 87 base->evsel = eventops[i]; 88 89 base->evbase = base->evsel->init(base); 90 } 91 92 if (base->evbase == NULL) { 93 event_warnx("%s: no event mechanism available", 94 __func__); 95 base->evsel = NULL; 96 event_base_free(base); 97 return NULL; 98 } 99 100 if (evutil_getenv_("EVENT_SHOW_METHOD")) 101 event_msgx("libevent using: %s", base->evsel->name); 102 103 /* allocate a single active event queue */ 104 if (event_base_priority_init(base, 1) < 0) { 105 event_base_free(base); 106 return NULL; 107 } 108 109 /* prepare for threading */ 110 111 #if !defined(EVENT__DISABLE_THREAD_SUPPORT) && !defined(EVENT__DISABLE_DEBUG_MODE) 112 event_debug_created_threadable_ctx_ = 1; 113 #endif 114 115 #ifndef EVENT__DISABLE_THREAD_SUPPORT 116 if (EVTHREAD_LOCKING_ENABLED() && 117 (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) { 118 int r; 119 EVTHREAD_ALLOC_LOCK(base->th_base_lock, 0); 120 EVTHREAD_ALLOC_COND(base->current_event_cond); 121 r = evthread_make_base_notifiable(base); 122 if (r<0) { 123 event_warnx("%s: Unable to make base notifiable.", __func__); 124 event_base_free(base); 125 return NULL; 126 } 127 } 128 #endif 129 130 #ifdef _WIN32 131 if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP)) 132 event_base_start_iocp_(base, cfg->n_cpus_hint); 133 #endif 134 135 return (base); 136 }
(1)调用mm_calloc函数分配一块大小为sizeof(struct event_base)的内存空间。
(2)如果形参cfg不为NULL,则将base.flags赋值为cfg->flags。
(3)第71-90行设置了实际使用的后端机制,for循环从遍历数组eventops,直到找到一个可用的后端为止,可以看一下eventops。
1 #ifdef EVENT__HAVE_EVENT_PORTS 2 extern const struct eventop evportops; 3 #endif 4 #ifdef EVENT__HAVE_SELECT 5 extern const struct eventop selectops; 6 #endif 7 #ifdef EVENT__HAVE_POLL 8 extern const struct eventop pollops; 9 #endif 10 #ifdef EVENT__HAVE_EPOLL 11 extern const struct eventop epollops; 12 #endif 13 #ifdef EVENT__HAVE_WORKING_KQUEUE 14 extern const struct eventop kqops; 15 #endif 16 #ifdef EVENT__HAVE_DEVPOLL 17 extern const struct eventop devpollops; 18 #endif 19 #ifdef _WIN32 20 extern const struct eventop win32ops; 21 #endif 22 23 /* Array of backends in order of preference. */ 24 static const struct eventop *eventops[] = { 25 #ifdef EVENT__HAVE_EVENT_PORTS 26 &evportops, 27 #endif 28 #ifdef EVENT__HAVE_WORKING_KQUEUE 29 &kqops, 30 #endif 31 #ifdef EVENT__HAVE_EPOLL 32 &epollops, 33 #endif 34 #ifdef EVENT__HAVE_DEVPOLL 35 &devpollops, 36 #endif 37 #ifdef EVENT__HAVE_POLL 38 &pollops, 39 #endif 40 #ifdef EVENT__HAVE_SELECT 41 &selectops, 42 #endif 43 #ifdef _WIN32 44 &win32ops, 45 #endif 46 NULL 47 };