libevent sample--分析及其源码阅读

来源:互联网 发布:python 提取文件名 编辑:程序博客网 时间:2024/06/08 02:30

time_test.c

1、 struct event_base *base=event_base_new();


<span style="font-size:18px;">struct event_base *event_base_new(void){struct event_base *base = NULL;struct event_config *cfg = event_config_new();if (cfg) {base = event_base_new_with_config(cfg);event_config_free(cfg);}return base;}</span>

struct event_base *event_base_new_with_config(const struct event_config *cfg){int i;struct event_base *base;int should_check_environment;#ifndef EVENT__DISABLE_DEBUG_MODEevent_debug_mode_too_late = 1;#endif                    //分配内存的同时还初始化if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) {event_warn("%s: calloc", __func__);return NULL;}if (cfg)base->flags = cfg->flags;should_check_environment =    !(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));{struct timeval tmp;int precise_time =    cfg && (cfg->flags & EVENT_BASE_FLAG_PRECISE_TIMER);int flags;if (should_check_environment && !precise_time) {precise_time = evutil_getenv_("EVENT_PRECISE_TIMER") != NULL;base->flags |= EVENT_BASE_FLAG_PRECISE_TIMER;}flags = precise_time ? EV_MONOT_PRECISE : 0;evutil_configure_monotonic_time_(&base->monotonic_timer, flags);gettime(base, &tmp);}min_heap_ctor_(&base->timeheap);base->sig.ev_signal_pair[0] = -1;base->sig.ev_signal_pair[1] = -1;base->th_notify_fd[0] = -1;base->th_notify_fd[1] = -1;TAILQ_INIT(&base->active_later_queue);evmap_io_initmap_(&base->io);evmap_signal_initmap_(&base->sigmap);event_changelist_init_(&base->changelist);base->evbase = NULL;if (cfg) {memcpy(&base->max_dispatch_time,    &cfg->max_dispatch_interval, sizeof(struct timeval));base->limit_callbacks_after_prio =    cfg->limit_callbacks_after_prio;} else {base->max_dispatch_time.tv_sec = -1;base->limit_callbacks_after_prio = 1;}if (cfg && cfg->max_dispatch_callbacks >= 0) {base->max_dispatch_callbacks = cfg->max_dispatch_callbacks;} else {base->max_dispatch_callbacks = INT_MAX;}if (base->max_dispatch_callbacks == INT_MAX &&    base->max_dispatch_time.tv_sec == -1)base->limit_callbacks_after_prio = INT_MAX;for (i = 0; eventops[i] && !base->evbase; i++) {if (cfg != NULL) {/* determine if this backend should be avoided */if (event_config_is_avoided_method(cfg,eventops[i]->name))continue;if ((eventops[i]->features & cfg->require_features)    != cfg->require_features)continue;}/* also obey the environment variables */if (should_check_environment &&    event_is_method_disabled(eventops[i]->name))continue;                 //函数操作集  整合各种io操作base->evsel = eventops[i];                 //evbase的初始化设置base->evbase = base->evsel->init(base);}if (base->evbase == NULL) {event_warnx("%s: no event mechanism available",    __func__);base->evsel = NULL;event_base_free(base);return NULL;}if (evutil_getenv_("EVENT_SHOW_METHOD"))event_msgx("libevent using: %s", base->evsel->name);/* allocate a single active event queue  事件优先级的设置*/if (event_base_priority_init(base, 1) < 0) {event_base_free(base);return NULL;}/* prepare for threading */#if !defined(EVENT__DISABLE_THREAD_SUPPORT) && !defined(EVENT__DISABLE_DEBUG_MODE)event_debug_created_threadable_ctx_ = 1;#endif#ifndef EVENT__DISABLE_THREAD_SUPPORTif (EVTHREAD_LOCKING_ENABLED() &&    (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) {int r;EVTHREAD_ALLOC_LOCK(base->th_base_lock, 0);EVTHREAD_ALLOC_COND(base->current_event_cond);                                                                                              /* <span style="font-family: Arial; font-size: 14px; line-height: 26px;">evthread_make_base_notifiable函数,使得libevent变成可通知的。只有在已经支持多线程的情况下才会调用                                                               evthread_make_base_notifiable函数的*/</span>r = evthread_make_base_notifiable(base);if (r<0) {event_warnx("%s: Unable to make base notifiable.", __func__);event_base_free(base);return NULL;}}#endif#ifdef _WIN32if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP))event_base_start_iocp_(base, cfg->n_cpus_hint);#endifreturn (base);}
//event.c文件 intevent_base_priority_init(struct event_base *base, int npriorities){int i;//由N_ACTIVE_CALLBACKS宏可以知道,本函数应该要在event_base_dispatch//函数调用前调用。不然将无法设置。if (N_ACTIVE_CALLBACKS(base) || npriorities < 1    || npriorities >= EVENT_MAX_PRIORITIES)return (-1);//之前和现在要设置的优先级数是一样的。if (npriorities == base->nactivequeues)return (0);//释放之前的,因为N_ACTIVE_CALLBACKS,所以没有active的event。//可以随便mm_freeif (base->nactivequeues) { mm_free(base->activequeues);base->nactivequeues = 0;}//分配一个优先级数组。base->activequeues = (struct event_list *)  mm_calloc(npriorities, sizeof(struct event_list));if (base->activequeues == NULL) {event_warn("%s: calloc", __func__);return (-1);}base->nactivequeues = npriorities;for (i = 0; i < base->nactivequeues; ++i) {TAILQ_INIT(&base->activequeues[i]);}return (0);}
因为event_base_dispatch函数会改动激活事件的个数,即会使得N_ACTIVE_CALLBACKS(base)为真。所以event_base_priority_init函数要在event_base_dispatch函数之前调用。此外要设置的优先级个数,要小于EVENT_MAX_PRIORITIES
intevthread_make_base_notifiable(struct event_base *base){int r;if (!base)return -1;EVBASE_ACQUIRE_LOCK(base, th_base_lock);r = evthread_make_base_notifiable_nolock_(base);EVBASE_RELEASE_LOCK(base, th_base_lock);return r;}
对于:通知主线程函数分析:

当主线程在执行event_base_dispatch进入多路IO复用函数时,会处于休眠状态,休眠前解锁。此时,其他线程可能想往event_base添加一个event,这个event可能是一般的IO event也可能是超时event。无论哪个,都需要及时告知主线程:有新的event要加进来。要实现这种功能就需要Libevent提供一种机制来提供唤醒主线程。

libevent提供的唤醒的主线程机制:

在struct event_base{

..................................

/* Notify main thread to wake up break, etc. */
/** True if the base already has a pending notify, and we don't need
* to add any more. */
int is_notify_pending;
/** A socketpair used by some th_notify functions to wake up the main
* thread. */
evutil_socket_t th_notify_fd[2];
/** An event used by some th_notify functions to wake up the main
* thread. */
struct event th_notify;
/** A function used to wake up the main thread from another thread. */
int (*th_notify_fn)(struct event_base *base);

...................

}

在event_base中提供一个IO event 专门用于唤醒主线程,当由其他线程有event 加入的时候,就往这个IO event中写入一个字节,此时主线程dispatch时,及检测到可读即唤醒主线程。

static intevthread_make_base_notifiable_nolock_(struct event_base *base){                                                                                                                                                                 //默认event 回调函数和默认通知函数void (*cb)(evutil_socket_t, short, void *);int (*notify)(struct event_base *);if (base->th_notify_fn != NULL) {/* The base is already notifiable: we're doing fine. */return 0;}#if defined(EVENT__HAVE_WORKING_KQUEUE)<span style="font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px; background-color: rgb(248, 248, 248);">  </span>if (base->evsel == &kqops && event_kq_add_notify_event_(base) == 0) {base->th_notify_fn = event_kq_notify_base_;/* No need to add an event here; the backend can wake * itself up just fine. */return 0;}#endif#ifdef EVENT__HAVE_EVENTFD<span style="font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px; background-color: rgb(248, 248, 248);">   </span><span class="comment" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 130, 0); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px; background-color: rgb(248, 248, 248);">//Libevent优先使用eventfd,创建一个文件描述符fd同时创建</span>base->th_notify_fd[0] = evutil_eventfd_(0,    EVUTIL_EFD_CLOEXEC|EVUTIL_EFD_NONBLOCK);if (base->th_notify_fd[0] >= 0) {base->th_notify_fd[1] = -1;notify = evthread_notify_base_eventfd;cb = evthread_notify_drain_eventfd;} else#endifif (evutil_make_internal_pipe_(base->th_notify_fd) == 0) {notify = evthread_notify_base_default;cb = evthread_notify_drain_default;} else {return -1;}          //设置回调函数base->th_notify_fn = notify;         调用event_assign初始化  类似于event_new。  cb为event的回调函数/* prepare an event that we can use for wakeup */event_assign(&base->th_notify, base, base->th_notify_fd[0], EV_READ|EV_PERSIST, cb, base);/* we need to mark this as internal event */base->th_notify.ev_flags |= EVLIST_INTERNAL;event_priority_set(&base->th_notify, 0);设置优先级  最高优先级        加入到event_base即th_notify中的base选中return event_add_nolock_(&base->th_notify, NULL, 0); }
启动notify:



0 0