• 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源码深度剖析七

  • 相关阅读:
    面向对象 (11)求交并集 判断字符形式
    软件工程 课程总结
    面向对象 (10)正则判邮箱
    面向对象 (9)计算时间差 找随机数范围内规律
    面向对象 (8)字符串出现字符个数统计 字母组成回文串判定
    面向对象 (7)中介买房 平均数异常处理
    面向对象 (6)买房付首款
    第16周作业
    第15周作业
    迟到的第14周作业
  • 原文地址:https://www.cnblogs.com/xiehongfeng100/p/4821605.html
Copyright © 2020-2023  润新知