libevent 源码分析event_base

在tcp通信中,会用到event_base这个结构体。

下面来看看这个结构体。

event_base_new(),创建event_base

/**
 * Create and return a new event_base to use with the rest of Libevent.
 * 创建并返回一个新的event_base 给libevent的其它部分使用。
 * @return a new event_base on success, or NULL on failure.
 * 成功的话,返回一个新的event_base, 失败返回NULL。
 * @see event_base_free(), event_base_new_with_config()
 */
EVENT2_EXPORT_SYMBOL
struct event_base *event_base_new(void);
truct 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;
}

通过上面的代码,可以知道,在创建event_base时,需要用到event_config对象。

 

结构体event_config.

/** Internal structure: describes the configuration we want for an event_base
 * that we're about to allocate. */ 内部结构体:描叙了我们准备分配的一个event_base的配置
struct event_config {
    TAILQ_HEAD(event_configq, event_config_entry) entries; //定义一个tail queue

    int n_cpus_hint;
    struct timeval max_dispatch_interval;
    int max_dispatch_callbacks;
    int limit_callbacks_after_prio;
    enum event_method_feature require_features;
    enum event_base_config_flag flags;
};

 

创建event_config对象,用到接口event_config_new

继续跟踪event_config_new

/**
   Allocates a new event configuration object.

   The event configuration object can be used to change the behavior of
   an event base.

   @return an event_config object that can be used to store configuration, or
     NULL if an error is encountered.
   @see event_base_new_with_config(), event_config_free(), event_config
*/
EVENT2_EXPORT_SYMBOL
struct event_config *event_config_new(void);
struct event_config *
event_config_new(void)
{
    struct event_config *cfg = mm_calloc(1, sizeof(*cfg));

    if (cfg == NULL)
        return (NULL);

    TAILQ_INIT(&cfg->entries);
    cfg->max_dispatch_interval.tv_sec = -1;
    cfg->max_dispatch_callbacks = INT_MAX;
    cfg->limit_callbacks_after_prio = 1;

    return (cfg);
}

 

获取到event_config对象后,可以开始创建event_base对象。

接口event_base_new_with_config.

/**
  Initialize the event API. 初始化接口

  Use event_base_new_with_config() to initialize a new event base, taking
  the specified configuration under consideration.  The configuration object
  can currently be used to avoid certain event notification mechanisms.
  根据预先制定的配置,用event_base_new_with_config() 来初始化一个新的event base。
  @param cfg the event configuration object event configuration 对象
  @return an initialized event_base that can be used to registering events,
     or NULL if no event base can be created with the requested event_config.
  一个初始化的event_base,可以用于注册events,也可能是NULL(当根据指定的event_config,没有创建成功event base)
  @see event_base_new(), event_base_free(), event_init(), event_assign()
*/
EVENT2_EXPORT_SYMBOL
struct event_base *event_base_new_with_config(const struct event_config *cfg);
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_MODE
    event_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;
            if (precise_time) {
                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;

        base->evsel = eventops[i];

        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_SUPPORT
    if (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);
        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 _WIN32
    if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP))
        event_base_start_iocp_(base, cfg->n_cpus_hint);
#endif

    /* initialize watcher lists */
    for (i = 0; i < EVWATCH_MAX; ++i)
        TAILQ_INIT(&base->watchers[i]);

    return (base);
}

至此获取到了一个初始化后的base。

这里可以看出base的创建和event_base_config有密切的关系,目前不对config进行深入的分析。

posted @ 2020-03-06 12:01  N_zero  阅读(307)  评论(0)    收藏  举报