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 /**@}*/ 

事件处理主循环

有待添加

 

参考资料

  libevent源码深度剖析六

  libevent源码深度剖析七

 

posted @ 2015-09-22 11:45  峰子_仰望阳光  阅读(4406)  评论(0编辑  收藏  举报