分析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 };
View Code

相关文章: