zoukankan      html  css  js  c++  java
  • libevent 库学习

    evutil:

      用于抽象不同平台网络实现差异的通用功能。

    event和event_base:

      libevent的核心,为各种平台特定的、基于事件的非阻塞 IO后端提供抽象API,让程序可以知道套接字何时已经准备好,可以读或者写,并且处理基本的超时功能,检测OS信号。用 libevent 函数之前需要分配一个或者多个 event_base 结构体。每个event_base 结构 体持有一个事件集合,可以检测以确定哪个事件是激活的。如果设置 event_base 使用锁,则可以安全地在多个线程中访问它 。然而,其事件循环只能 运行在一个线程中。如果需要用多个线程检测 IO,则需要为每个线程使用一个 event_base。默认情况下,event_base_loop()函数运行 event_base 直到其中没有已经注册的事件为止。执行循环的时候 ,函数重复地检查是否有任何已经注册的事件被触发 (比如说,读事件 的文件描述符已经就绪,可以读取了;或者超时事件的超时时间即将到达)。如果有事件被触发,函数标记被触发的事件为 “激活的”,并且执行这些事件

    vent_base处理过程主要如下:

      1.调用event_base_new()创建一个event_base

      2.注册了某些事件的 event_base

      3.调用event_base_loop()或者event_base_dispatch()函数,循环等待事件并且通知事件的发生

      4.调用event_base_loopexit()或者event_base_loopbreak()移除所有已注册的事件之前停止活动的事件循环

      5.使用完 event_base 之后,使用event_base_free()进行释放

    bufferevent:

      为libevent基于事件的核心提供使用更方便的封装。除了通知程序套接字已经准备好读写之外,还让程序可以请求缓冲的读写操作,可以知道何时IO已经真正发生。( bufferevent接口有多个后端, 可以采用系统能够提供的更快的非阻塞 IO方式,如Windows中的IOCP。)


    evbuffer:在bufferevent层之下实现了缓冲功能,并且提供了方便有效的访问函数

    Libevent是基于事件驱动(event-driven)的,从名字也可以看到event是整个库的核心。event就是Reactor框架中的事件处理程序组件;它提供了函数接口,供Reactor在事件发生时调用,以执行相应的事件处理,通常它会绑定一个有效的句柄。
       event结构在event.h中申明,在event_struct.h中定义。具体结构如下:

     1 struct event {
     2     struct event_callback ev_evcallback;  /*回调函数结构体*/
     3 
     4     /* for managing timeouts 
     5      * 如果是timeout事件,它们是event在小根堆中的索引,
     6      * libevent使用小根堆来管理定时事件
     7      */
     8     union {
     9         TAILQ_ENTRY(event) ev_next_with_common_timeout;
    10         int min_heap_idx;
    11     } ev_timeout_pos;
    12     evutil_socket_t ev_fd;    /*对于I/O事件,是绑定的文件描述符;对于signal事件,是绑定的信号*/
    13 
    14     short ev_events;    /*event关注的事件类型*/
    15     short ev_res;        /* 记录了当前激活事件的类型result passed to event callback */
    16 
    17     struct event_base *ev_base;    /*该事件所属的反应堆实例,这是一个event_base结构体*/
    18 
    19     union {
    20         /* used for io events */
    21         struct {
    22             LIST_ENTRY (event) ev_io_next;
    23             struct timeval ev_timeout;
    24         } ev_io;
    25 
    26         /* used by signal events */
    27         struct {
    28             LIST_ENTRY (event) ev_signal_next;
    29             short ev_ncalls;    /*事件就绪执行时,调用ev_callback的次数,通常为1*/
    30             /* Allows deletes in callback 指针,通常指向ev_ncalls或者为NULL*/
    31             short *ev_pncalls;
    32         } ev_signal;
    33     } ev_;    /*针对不同类型的事件设置链表记录*/
    34 
    35 
    36     struct timeval ev_timeout;    /*timeout事件的超市值*/
    37 };

     在event结构中,有一个指向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 handler code. */
     16     struct evsig_info sig;
     17 
     18     /*一些计数数据*/
     19     /** Number of virtual events */
     20     int virtual_event_count;
     21     /** Maximum number of virtual events active */
     22     int virtual_event_count_max;
     23     /** Number of total events added to this event_base */
     24     int event_count;
     25     /** Maximum number of total events added to this event_base */
     26     int event_count_max;
     27     /** Number of total events active in this event_base */
     28     int event_count_active;
     29     /** Maximum number of total events active in this event_base */
     30     int event_count_active_max;
     31 
     32     /*事件循环控制参数*/
     33     /** Set if we should terminate the loop once we're done processing
     34      * events. */
     35     int event_gotterm;
     36     /** Set if we should terminate the loop immediately */
     37     int event_break;
     38     /** Set if we should start a new instance of the loop immediately. */
     39     int event_continue;
     40 
     41     /** 优先级 The currently running priority of events */
     42     int event_running_priority;
     43 
     44     /** Set if we're running the event_base_loop function, to prevent
     45      * reentrant invocation. */
     46     int running_loop;
     47 
     48     /** Set to the number of deferred_cbs we've made 'active' in the
     49      * loop.  This is a hack to prevent starvation; it would be smarter
     50      * to just use event_config_set_max_dispatch_interval's max_callbacks
     51      * feature */
     52     int n_deferreds_queued;
     53 
     54     /* 此处用链表管理激活的事件 Active event management. */
     55     /** An array of nactivequeues queues for active event_callbacks (ones
     56      * that have triggered, and whose callbacks need to be called).  Low
     57      * priority numbers are more important, and stall higher ones.
     58      */
     59     struct evcallback_list *activequeues;
     60     /** The length of the activequeues array */
     61     int nactivequeues;
     62     /** A list of event_callbacks that should become active the next time
     63      * we process events, but not this time. */
     64     struct evcallback_list active_later_queue;
     65 
     66     /* 超时控制 common timeout logic */
     67 
     68     /** An array of common_timeout_list* for all of the common timeout
     69      * values we know. */
     70     struct common_timeout_list **common_timeout_queues;
     71     /** The number of entries used in common_timeout_queues */
     72     int n_common_timeouts;
     73     /** The total size of common_timeout_queues. */
     74     int n_common_timeouts_allocated;
     75 
     76     /** IO事件 Mapping from file descriptors to enabled (added) events */
     77     struct event_io_map io;
     78 
     79     /** 信号事件 Mapping from signal numbers to enabled (added) events. */
     80     struct event_signal_map sigmap;
     81 
     82     /** 超时事件 Priority queue of events with timeouts. */
     83     struct min_heap timeheap;
     84 
     85     /** 时间戳记录 Stored timeval: used to avoid calling gettimeofday/clock_gettime
     86      * too often. */
     87     struct timeval tv_cache;
     88 
     89     struct evutil_monotonic_timer monotonic_timer;
     90 
     91     /** Difference between internal time (maybe from clock_gettime) and
     92      * gettimeofday. */
     93     struct timeval tv_clock_diff;
     94     /** Second in which we last updated tv_clock_diff, in monotonic time. */
     95     time_t last_updated_clock_diff;
     96 
     97 #ifndef EVENT__DISABLE_THREAD_SUPPORT
     98     /* threading support */
     99     /** The thread currently running the event_loop for this base */
    100     unsigned long th_owner_id;
    101     /** A lock to prevent conflicting accesses to this event_base */
    102     void *th_base_lock;
    103     /** A condition that gets signalled when we're done processing an
    104      * event with waiters on it. */
    105     void *current_event_cond;
    106     /** Number of threads blocking on current_event_cond. */
    107     int current_event_waiters;
    108 #endif
    109     /** The event whose callback is executing right now */
    110     struct event_callback *current_event;
    111 
    112 #ifdef _WIN32
    113     /** IOCP support structure, if IOCP is enabled. */
    114     struct event_iocp_port *iocp;
    115 #endif
    116 
    117     /** Flags that this base was configured with */
    118     enum event_base_config_flag flags;
    119 
    120     struct timeval max_dispatch_time;
    121     int max_dispatch_callbacks;
    122     int limit_callbacks_after_prio;
    123 
    124     /* Notify main thread to wake up break, etc. */
    125     /** True if the base already has a pending notify, and we don't need
    126      * to add any more. */
    127     int is_notify_pending;
    128     /** A socketpair used by some th_notify functions to wake up the main
    129      * thread. */
    130     evutil_socket_t th_notify_fd[2];
    131     /** An event used by some th_notify functions to wake up the main
    132      * thread. */
    133     struct event th_notify;
    134     /** A function used to wake up the main thread from another thread. */
    135     int (*th_notify_fn)(struct event_base *base);
    136 
    137     /** Saved seed for weak random number generator. Some backends use
    138      * this to produce fairness among sockets. Protected by th_base_lock. */
    139     struct evutil_weakrand_state weakrand_seed;
    140 
    141     /** List of event_onces that have not yet fired. */
    142     LIST_HEAD(once_event_list, event_once) once_events;
    143 
    144 };

    evsel和evbase这两个字段的设置可能会让人有些迷惑,这里你可以把evsel和evbase看作是类和静态函数的关系,比如添加事件时的调用行为:evsel->add(evbase, ev),实际执行操作的是evbase;这相当于class::add(instance, ev),instance就是class的一个对象实例。evsel指向了全局变量static const struct eventop *eventops[]中的一个;
    前面也说过,libevent将系统提供的I/O demultiplex机制统一封装成了eventop结构;因此eventops[]包含了select、poll、kequeue和epoll等等其中的若干个全局实例对象。evbase实际上是一个eventop实例对象。eventop会根据当前编译环境选择可用的类型添加至数组中以供选择,其实现在编译过程中进行,对用户来说是完全封闭不可见的。具体说明在后文中会详细介绍。这里给出其中用到的event_top结构体如下:

     1 /** Structure to define the backend of a given event_base. */
     2 struct eventop {
     3 
     4     /** 名字 The name of this backend. */
     5     const char *name;
     6     
     7     /** 初始化 Function to set up an event_base to use this backend.  It should
     8      * create a new structure holding whatever information is needed to
     9      * run the backend, and return it.  The returned pointer will get
    10      * stored by event_init into the event_base.evbase field.  On failure,
    11      * this function should return NULL. */
    12     void *(*init)(struct event_base *);
    13     
    14     /** 注册 Enable reading/writing on a given fd or signal.  'events' will be
    15      * the events that we're trying to enable: one or more of EV_READ,
    16      * EV_WRITE, EV_SIGNAL, and EV_ET.  'old' will be those events that
    17      * were enabled on this fd previously.  'fdinfo' will be a structure
    18      * associated with the fd by the evmap; its size is defined by the
    19      * fdinfo field below.  It will be set to 0 the first time the fd is
    20      * added.  The function should return 0 on success and -1 on error.
    21      */
    22     int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
    23     
    24     /** 删除 As "add", except 'events' contains the events we mean to disable. */
    25     int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
    26     
    27     /** 事件分发 Function to implement the core of an event loop.  It must see which
    28         added events are ready, and cause event_active to be called for each
    29         active event (usually via event_io_active or such).  It should
    30         return 0 on success and -1 on error.
    31      */
    32     int (*dispatch)(struct event_base *, struct timeval *);
    33     
    34     /** 释放资源 Function to clean up and free our data from the event_base. */
    35     void (*dealloc)(struct event_base *);
    36     
    37     /** 标记位 Flag: set if we need to reinitialize the event base after we fork.
    38      */
    39     int need_reinit;
    40     
    41     /**支持的特性,根据操作系统不同而不同 Bit-array of supported event_method_features that this backend 
    42     can provide. */
    43     enum event_method_feature features;
    44     
    45     /** 额外信息记录 Length of the extra information we should record for each fd that
    46         has one or more active events.  This information is recorded
    47         as part of the evmap entry for each fd, and passed as an argument
    48         to the add and del functions above.
    49      */
    50     size_t fdinfo_len;
    51 };

    接口函数分析
    (1)event_new()函数
      分配并赋值新的event结构,准备用于添加和删除,即event_add() 或 event_del()。
    参数包括:
      (1)base 新事件属于的事件库event_base
      (2)fd 文件描述符或者信号
      (3)events 对应的控制事件: bitfield of EV_READ, EV_WRITE, EV_SIGNAL, EV_PERSIST, EV_ET.
      (4)callback 事件发生时的回调函数
      (5)callback_arg 回调函数传参
      fd和event决定了什么情况会触发该事件,回调函数和回调传参决定了事件触发时应做什么。
    返回值:
      返回新的结构体event,必须由event_free()释放或者置为NULL
      若events包括 EV_READ, EV_WRITE, 或 EV_READ|EV_WRITE,则fd是文件描述符或者套接字,并可以用于读、写。若event包括EV_SIGNAL则fd是信号事件。若没有任何标记,则事件仅可以在超时或手动激活时(调用event_actifve())生效。
      代码非常的简单,源码和分析如下所示:

     1 /*新建事件*/
     2 struct event *
     3 event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg)
     4 {
     5     /*创建指针*/
     6     struct event *ev;
     7     ev = mm_malloc(sizeof(struct event));
     8 
     9     /*错误判断*/
    10     if (ev == NULL)
    11         return (NULL);
    12 
    13     /*调用event_assign*/
    14     if (event_assign(ev, base, fd, events, cb, arg) < 0) {
    15         mm_free(ev);
    16         return (NULL);
    17     }
    18 
    19     return (ev);
    20 }

    (2)event_free()函数
      源码和分析如下所示:

    /*释放事件(包括资源释放)*/
    void
    event_free(struct event *ev)
    {
        /* This is disabled, so that events which have been finalized be a
         * valid target for event_free(). That's */
        // event_debug_assert_is_setup_(ev);
    
        /* make sure that this event won't be coming back to haunt us. */
        event_d el(ev);
        event_debug_note_teardown_(ev);/*关闭针对ev的debug*/
        mm_free(ev);
    
    }

    (3)event_assign()函数
      源码和分析如下所示:

    /*事件的配置:赋值以及异常处理*/
    int
    event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
    {
        /*异常处理*/
        if (!base)
            base = current_base;
        if (arg == &event_self_cbarg_ptr_)
            arg = ev;
    
        event_debug_assert_not_added_(ev);
    
        /*将事件的堆属性赋值为已有的事件堆base*/
        ev->ev_base = base;
    
        /*赋值*/
        ev->ev_callback = callback;
        ev->ev_arg = arg;
        ev->ev_fd = fd;
        ev->ev_events = events;
        ev->ev_res = 0;
        ev->ev_flags = EVLIST_INIT;
        ev->ev_ncalls = 0;
        ev->ev_pncalls = NULL;
    
        /*根据事件类型分开进行错误判断*/
        /*信号类型*/
        if (events & EV_SIGNAL) {
            /*信号类型不允许有IO类型的读写关闭标记位*/
            if ((events & (EV_READ|EV_WRITE|EV_CLOSED)) != 0) {
                event_warnx("%s: EV_SIGNAL is not compatible with "
                    "EV_READ, EV_WRITE or EV_CLOSED", __func__);
                return -1;
            }
            ev->ev_closure = EV_CLOSURE_EVENT_SIGNAL;
        } else {
            /*对永久事件,超时置零*/
            if (events & EV_PERSIST) {
                evutil_timerclear(&ev->ev_io_timeout);
                ev->ev_closure = EV_CLOSURE_EVENT_PERSIST;
            } else {
                ev->ev_closure = EV_CLOSURE_EVENT;
            }
        }
    
        min_heap_elem_init_(ev);
    
        /*优先级:默认放在队列中间*/
        if (base != NULL) {
            /* by default, we put new events into the middle priority */
            ev->ev_pri = base->nactivequeues / 2;
        }
    
        /*debug功能开启*/
        event_debug_note_setup_(ev);
    
        return 0;
    }

    (4)event_get_assignment()函数
      源码和分析如下所示:

    /*获取event的属性:包括事件堆event_base, IO事件的fd, 信号事件的信息,回调函数等*/
    void
    event_get_assignment(const struct event *event, struct event_base **base_out, evutil_socket_t *fd_out, short *events_out, event_callback_fn *callback_out, void **arg_out)
    {
        event_debug_assert_is_setup_(event);
    
        if (base_out)
            *base_out = event->ev_base;
        if (fd_out)
            *fd_out = event->ev_fd;
        if (events_out)
            *events_out = event->ev_events;
        if (callback_out)
            *callback_out = event->ev_callback;
        if (arg_out)
            *arg_out = event->ev_arg;
    }

    其中调用的event_add_nolock_(),该函数较为复杂,源码和分析如下:

      1 /* Implementation function to add an event.  Works just like event_add,
      2  * except: 1) it requires that we have the lock.  2) if tv_is_absolute is set,
      3  * we treat tv as an absolute time, not as an interval to add to the current
      4  * time */
      5 int
      6 event_add_nolock_(struct event *ev, const struct timeval *tv,
      7     int tv_is_absolute)
      8 {
      9     struct event_base *base = ev->ev_base;
     10     int res = 0;
     11     int notify = 0;
     12 
     13     /*上锁判断,debug判断*/
     14     EVENT_BASE_ASSERT_LOCKED(base);
     15     event_debug_assert_is_setup_(ev);
     16 
     17     event_debug((
     18          "event_add: event: %p (fd "EV_SOCK_FMT"), %s%s%s%scall %p",
     19          ev,
     20          EV_SOCK_ARG(ev->ev_fd),
     21          ev->ev_events & EV_READ ? "EV_READ " : " ",
     22          ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
     23          ev->ev_events & EV_CLOSED ? "EV_CLOSED " : " ",
     24          tv ? "EV_TIMEOUT " : " ",
     25          ev->ev_callback));
     26 
     27     EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));
     28 
     29     if (ev->ev_flags & EVLIST_FINALIZING) {
     30         /* XXXX debug */
     31         return (-1);
     32     }
     33 
     34     /*
     35      * 新的timer事件,调用timer heap接口在堆上预留一个位置  
     36      * 注:这样能保证该操作的原子性:  
     37      * 向系统I/O机制注册可能会失败,而当在堆上预留成功后,  
     38      * 定时事件的添加将肯定不会失败;  
     39      * 而预留位置的可能结果是堆扩充,但是内部元素并不会改变
     40      * prepare for timeout insertion further below, if we get a
     41      * failure on any step, we should not change any state.
     42      */
     43     if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
     44         if (min_heap_reserve_(&base->timeheap,
     45             1 + min_heap_size_(&base->timeheap)) == -1)
     46             return (-1);  /* ENOMEM == errno */
     47     }
     48 
     49 
     50     /* If the main thread is currently executing a signal event's
     51      * callback, and we are not the main thread, then we want to wait
     52      * until the callback is done before we mess with the event, or else
     53      * we can race on ev_ncalls and ev_pncalls below. */
     54 #ifndef EVENT__DISABLE_THREAD_SUPPORT
     55     if (base->current_event == event_to_event_callback(ev) &&
     56         (ev->ev_events & EV_SIGNAL)
     57         && !EVBASE_IN_THREAD(base)) {
     58         ++base->current_event_waiters;
     59         EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
     60     }
     61 #endif
     62 
     63     /*如果事件ev不在已注册或者激活链表中,则调用evbase注册事件 */
     64     if ((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL)) &&
     65         !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
     66         
     67         /*判断io或者信号分类添加*/
     68         if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
     69             res = evmap_io_add_(base, ev->ev_fd, ev);
     70         else if (ev->ev_events & EV_SIGNAL)
     71             res = evmap_signal_add_(base, (int)ev->ev_fd, ev);
     72         
     73         /*// 注册成功,插入event到已注册链表中 */
     74         if (res != -1)
     75             event_queue_insert_inserted(base, ev);
     76         if (res == 1) {
     77             /* evmap says we need to notify the main thread. */
     78             notify = 1;
     79             res = 0;
     80         }
     81     }
     82 
     83     /* 准备添加定时事件
     84      * we should change the timeout state only if the previous event
     85      * addition succeeded.
     86      */
     87     if (res != -1 && tv != NULL) {
     88         struct timeval now;
     89         int common_timeout;
     90 #ifdef USE_REINSERT_TIMEOUT
     91         int was_common;
     92         int old_timeout_idx;
     93 #endif
     94 
     95         /* 
     96          * for persistent timeout events, we remember the
     97          * timeout value and re-add the event.
     98          *
     99          * If tv_is_absolute, this was already set.
    100          */
    101         if (ev->ev_closure == EV_CLOSURE_EVENT_PERSIST && !tv_is_absolute)
    102             ev->ev_io_timeout = *tv;
    103 
    104         /*EVLIST_TIMEOUT表明event已经在定时器堆中了,删除旧的*/
    105 #ifndef USE_REINSERT_TIMEOUT
    106         if (ev->ev_flags & EVLIST_TIMEOUT) {
    107             event_queue_remove_timeout(base, ev);
    108         }
    109 #endif
    110 
    111         /* 如果事件已经是就绪状态则从激活链表中删除 
    112          * Check if it is active due to a timeout.  Rescheduling
    113          * this timeout before the callback can be executed
    114          * removes it from the active list. */
    115         if ((ev->ev_flags & EVLIST_ACTIVE) &&
    116             (ev->ev_res & EV_TIMEOUT)) {
    117             if (ev->ev_events & EV_SIGNAL) {
    118                 /* See if we are just active executing
    119                  * this event in a loop
    120                  * 将ev_callback调用次数设置为0以终止循环  
    121                  */
    122                 if (ev->ev_ncalls && ev->ev_pncalls) {
    123                     /* Abort loop */
    124                     *ev->ev_pncalls = 0;
    125                 }
    126             }
    127 
    128             event_queue_remove_active(base, event_to_event_callback(ev));
    129         }
    130 
    131         /* 计算时间,并插入到timer根堆中 */
    132         gettime(base, &now);
    133 
    134         common_timeout = is_common_timeout(tv, base);
    135 #ifdef USE_REINSERT_TIMEOUT
    136         was_common = is_common_timeout(&ev->ev_timeout, base);
    137         old_timeout_idx = COMMON_TIMEOUT_IDX(&ev->ev_timeout);
    138 #endif
    139 
    140         if (tv_is_absolute) {
    141             ev->ev_timeout = *tv;
    142         } else if (common_timeout) {
    143             struct timeval tmp = *tv;
    144             tmp.tv_usec &= MICROSECONDS_MASK;
    145             evutil_timeradd(&now, &tmp, &ev->ev_timeout);
    146             ev->ev_timeout.tv_usec |=
    147                 (tv->tv_usec & ~MICROSECONDS_MASK);
    148         } else {
    149             evutil_timeradd(&now, tv, &ev->ev_timeout);
    150         }
    151 
    152         event_debug((
    153              "event_add: event %p, timeout in %d seconds %d useconds, call %p",
    154              ev, (int)tv->tv_sec, (int)tv->tv_usec, ev->ev_callback));
    155 
    156 #ifdef USE_REINSERT_TIMEOUT
    157         event_queue_reinsert_timeout(base, ev, was_common, common_timeout, old_timeout_idx);
    158 #else
    159         event_queue_insert_timeout(base, ev);
    160 #endif
    161 
    162         if (common_timeout) {
    163             struct common_timeout_list *ctl =
    164                 get_common_timeout_list(base, &ev->ev_timeout);
    165             if (ev == TAILQ_FIRST(&ctl->events)) {
    166                 common_timeout_schedule(ctl, &now, ev);
    167             }
    168         } else {
    169             struct event* top = NULL;
    170             /* See if the earliest timeout is now earlier than it
    171              * was before: if so, we will need to tell the main
    172              * thread to wake up earlier than it would otherwise.
    173              * We double check the timeout of the top element to
    174              * handle time distortions due to system suspension.
    175              */
    176             if (min_heap_elt_is_top_(ev))
    177                 notify = 1;
    178             else if ((top = min_heap_top_(&base->timeheap)) != NULL &&
    179                      evutil_timercmp(&top->ev_timeout, &now, <))
    180                 notify = 1;
    181         }
    182     }
    183 
    184     /* if we are not in the right thread, we need to wake up the loop */
    185     if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
    186         evthread_notify_base(base);
    187 
    188     event_debug_note_add_(ev);
    189 
    190     return (res);
    191 }

    (6)event_del()函数
      源码和分析如下所示:

    int
    event_del(struct event *ev)
    {
        return event_del_(ev, EVENT_DEL_AUTOBLOCK);
    }
     1 static int
     2 event_del_(struct event *ev, int blocking)
     3 {
     4     int res;
     5     struct event_base *base = ev->ev_base;
     6 
     7     /*异常处理*/
     8     if (EVUTIL_FAILURE_CHECK(!base)) {
     9         event_warnx("%s: event has no event_base set.", __func__);
    10         return -1;
    11     }
    12 
    13     /*上锁*/
    14     EVBASE_ACQUIRE_LOCK(base, th_base_lock);
    15     res = event_del_nolock_(ev, blocking);
    16     EVBASE_RELEASE_LOCK(base, th_base_lock);
    17 
    18     return (res);
    19 }

    真正的删除和添加一样,在上锁之后调用函数执行:

      1 /** 事件删除 Helper for event_del: always called with th_base_lock held.
      2  *
      3  * "blocking" must be one of the EVENT_DEL_{BLOCK, NOBLOCK, AUTOBLOCK,
      4  * EVEN_IF_FINALIZING} values. See those for more information.
      5  */
      6 int
      7 event_del_nolock_(struct event *ev, int blocking)
      8 {
      9     struct event_base *base;
     10     int res = 0, notify = 0;
     11 
     12     event_debug(("event_del: %p (fd "EV_SOCK_FMT"), callback %p",
     13         ev, EV_SOCK_ARG(ev->ev_fd), ev->ev_callback));
     14 
     15     /* 异常处理,ev_base为NULL,表明ev没有被注册 
     16      * An event without a base has not been added 
     17      */
     18     if (ev->ev_base == NULL)
     19         return (-1);
     20 
     21     EVENT_BASE_ASSERT_LOCKED(ev->ev_base);
     22 
     23     if (blocking != EVENT_DEL_EVEN_IF_FINALIZING) {
     24         if (ev->ev_flags & EVLIST_FINALIZING) {
     25             /* XXXX Debug */
     26             return 0;
     27         }
     28     }
     29 
     30     base = ev->ev_base;
     31 
     32     EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));
     33 
     34     /* 终止循环 See if we are just active executing this event in a loop */
     35     if (ev->ev_events & EV_SIGNAL) {
     36         if (ev->ev_ncalls && ev->ev_pncalls) {
     37             /* Abort loop */
     38             *ev->ev_pncalls = 0;
     39         }
     40     }
     41 
     42     if (ev->ev_flags & EVLIST_TIMEOUT) {
     43         /* 从超时队列中删除
     44          * NOTE: We never need to notify the main thread because of a
     45          * deleted timeout event: all that could happen if we don't is
     46          * that the dispatch loop might wake up too early.  But the
     47          * point of notifying the main thread _is_ to wake up the
     48          * dispatch loop early anyway, so we wouldn't gain anything by
     49          * doing it.
     50          */
     51         event_queue_remove_timeout(base, ev);
     52     }
     53 
     54     /*从激活/等待激活队列中删除*/
     55     if (ev->ev_flags & EVLIST_ACTIVE)
     56         event_queue_remove_active(base, event_to_event_callback(ev));
     57     else if (ev->ev_flags & EVLIST_ACTIVE_LATER)
     58         event_queue_remove_active_later(base, event_to_event_callback(ev));
     59 
     60     /*从对应的链表中删除事件 */
     61     if (ev->ev_flags & EVLIST_INSERTED) {
     62         event_queue_remove_inserted(base, ev);
     63         if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
     64             res = evmap_io_del_(base, ev->ev_fd, ev);
     65         else
     66             res = evmap_signal_del_(base, (int)ev->ev_fd, ev);
     67         if (res == 1) {
     68             /* evmap says we need to notify the main thread. */
     69             notify = 1;
     70             res = 0;
     71         }
     72         /* If we do not have events, let's notify event base so it can
     73          * exit without waiting */
     74         if (!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base))
     75             notify = 1;
     76     }
     77 
     78     /* 多线程情况下,判断是否在该线程执行 if we are not in the right thread, we need to wake up the loop */
     79     if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
     80         evthread_notify_base(base);
     81 
     82     event_debug_note_del_(ev);
     83 
     84     /* If the main thread is currently executing this event's callback,
     85      * and we are not the main thread, then we want to wait until the
     86      * callback is done before returning. That way, when this function
     87      * returns, it will be safe to free the user-supplied argument.
     88      */
     89 #ifndef EVENT__DISABLE_THREAD_SUPPORT
     90     if (blocking != EVENT_DEL_NOBLOCK &&
     91         base->current_event == event_to_event_callback(ev) &&
     92         !EVBASE_IN_THREAD(base) &&
     93         (blocking == EVENT_DEL_BLOCK || !(ev->ev_events & EV_FINALIZE))) {
     94         ++base->current_event_waiters;
     95         EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
     96     }
     97 #endif
     98 
     99     return (res);
    100 }

    (7)event_active()函数
      源码和分析如下所示:

    void
    event_active(struct event *ev, int res, short ncalls)
    {
        /*异常处理*/
        if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
            event_warnx("%s: event has no event_base set.", __func__);
            return;
        }
    
        /*上锁*/
        EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
    
        event_debug_assert_is_setup_(ev);
    
        event_active_nolock_(ev, res, ncalls);
    
        EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
    }

    event_active_nolock_()代码如下:

     1 /*激活事件*/
     2 void
     3 event_active_nolock_(struct event *ev, int res, short ncalls)
     4 {
     5     struct event_base *base;
     6 
     7     event_debug(("event_active: %p (fd "EV_SOCK_FMT"), res %d, callback %p",
     8         ev, EV_SOCK_ARG(ev->ev_fd), (int)res, ev->ev_callback));
     9 
    10     base = ev->ev_base;
    11     EVENT_BASE_ASSERT_LOCKED(base);
    12 
    13     /*标记为终止则无法激活*/
    14     if (ev->ev_flags & EVLIST_FINALIZING) {
    15         /* XXXX debug */
    16         return;
    17     }
    18 
    19     /*根据标记位判断立刻激活或者稍后激活*/
    20     switch ((ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
    21     default:
    22     case EVLIST_ACTIVE|EVLIST_ACTIVE_LATER:
    23         EVUTIL_ASSERT(0);
    24         break;
    25     case EVLIST_ACTIVE:
    26         /* We get different kinds of events, add them together */
    27         ev->ev_res |= res;
    28         return;
    29     case EVLIST_ACTIVE_LATER:
    30         ev->ev_res |= res;
    31         break;
    32     case 0:
    33         ev->ev_res = res;
    34         break;
    35     }
    36 
    37     if (ev->ev_pri < base->event_running_priority)
    38         base->event_continue = 1;
    39 
    40     if (ev->ev_events & EV_SIGNAL) {
    41 #ifndef EVENT__DISABLE_THREAD_SUPPORT
    42         if (base->current_event == event_to_event_callback(ev) &&
    43             !EVBASE_IN_THREAD(base)) {
    44             ++base->current_event_waiters;
    45             EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
    46         }
    47 #endif
    48         ev->ev_ncalls = ncalls;
    49         ev->ev_pncalls = NULL;
    50     }
    51 
    52     /*将事件添加入激活列表中*/
    53     event_callback_activate_nolock_(base, event_to_event_callback(ev));
    54 }

    (8)event_pending()函数
      源码和分析如下所示:

     1 /* 检测某事件是否待发生,返回标记位
     2  * Checks if a specific event is pending or scheduled.
     3  */
     4 
     5 int
     6 event_pending(const struct event *ev, short event, struct timeval *tv)
     7 {
     8     int flags = 0;
     9 
    10     /*异常检测*/
    11     if (EVUTIL_FAILURE_CHECK(ev->ev_base == NULL)) {
    12         event_warnx("%s: event has no event_base set.", __func__);
    13         return 0;
    14     }
    15 
    16     EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
    17     event_debug_assert_is_setup_(ev);
    18 
    19     /*检查标记位*/
    20     if (ev->ev_flags & EVLIST_INSERTED)
    21         flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL));
    22     if (ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))
    23         flags |= ev->ev_res;
    24     if (ev->ev_flags & EVLIST_TIMEOUT)
    25         flags |= EV_TIMEOUT;
    26 
    27     event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL);
    28 
    29     /* 添加超时 See if there is a timeout that we should report */
    30     if (tv != NULL && (flags & event & EV_TIMEOUT)) {
    31         struct timeval tmp = ev->ev_timeout;
    32         tmp.tv_usec &= MICROSECONDS_MASK;
    33         /* correctly remamp to real time */
    34         evutil_timeradd(&ev->ev_base->tv_clock_diff, &tmp, tv);
    35     }
    36 
    37     EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
    38 
    39     return (flags & event);
    40 }

    (9)event_priority_set()函数
      源码和分析如下所示:

     1 /* 设置优先级
     2  * Set's the priority of an event - if an event is already scheduled
     3  * changing the priority is going to fail.
     4  */
     5 
     6 int
     7 event_priority_set(struct event *ev, int pri)
     8 {
     9     event_debug_assert_is_setup_(ev);
    10 
    11     /*优先级设置对已激活的事件无效*/
    12     if (ev->ev_flags & EVLIST_ACTIVE)
    13         return (-1);
    14     if (pri < 0 || pri >= ev->ev_base->nactivequeues)
    15         return (-1);
    16 
    17     ev->ev_pri = pri;
    18 
    19     return (0);
    20 }
  • 相关阅读:
    2017/07/25 工作日志
    2017/07/27 工作日志
    2017/07/31 工作日志
    2017/07/26 工作日志
    2017/07/28 工作日志
    远程客户端由于元数据地址主机名为服务器计算机名而无法解析WCF服务元数据的解决办法
    两步实现SQLSERVER版本降级
    dll版本号相同,提示加载dll失败
    silverlight登陆页面的小细节【自动设置焦点,回车登陆】
    Silverlight向aspx传值
  • 原文地址:https://www.cnblogs.com/mysky007/p/12298260.html
Copyright © 2011-2022 走看看