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 }