码迷,mamicode.com
首页 > 其他好文 > 详细

Libevent源码分析-event_base

时间:2015-08-18 22:44:01      阅读:124      评论:0      收藏:0      [点我收藏+]

标签:libevent   event-base   reactor   

前面介绍了event,本节介绍Reactor的核心结构:event_base,它在event-internal.h中。
event_base是整个libevent的核心,它持有所有注册的事件,并负责通知激活的事件。

event_base数据结构

struct event_base {
    const struct eventop *evsel;
    void *evbase;
    struct event_changelist changelist;
    const struct eventop *evsigsel;
    struct evsig_info sig;

    int virtual_event_count;
    int event_count;
    int event_count_active;
    //...

    int event_running_priority;


    struct event_list *activequeues;
    int nactivequeues;

    struct common_timeout_list **common_timeout_queues;
    int n_common_timeouts;
    int n_common_timeouts_allocated;

    /** Mapping from file descriptors to enabled (added) events */
    struct event_io_map io;

    /** Mapping from signal numbers to enabled (added) events. */
    struct event_signal_map sigmap;

    /** All events that have been enabled (added) in this event_base */
    struct event_list eventqueue;

    /** Stored timeval; used to detect when time is running backwards. */
    struct timeval event_tv;

    /** Priority queue of events with timeouts. */
    struct min_heap timeheap;

    /** Stored timeval: used to avoid calling gettimeofday/clock_gettime
     * too often. */
    struct timeval tv_cache;


    /* 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);
};

略去了部分代码,看一下主要结构和逻辑:
1、eventtop是event_base的后端,它里面是函数指针,具体操作为IO复用的一些操作

struct eventop {
    /** The name of this backend. */
    const char *name;

    void *(*init)(struct event_base *);//初始化

    int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);//添加

    int (*dispatch)(struct event_base *, struct timeval *);//删除

    int need_reinit;//是否需要再次初始化

    enum event_method_feature features;

    size_t fdinfo_len;
};

这些具体的操作是select、poll、epoll等,以epoll初始化eventtop结构为例(在epoll.c中)

static void *epoll_init(struct event_base *);
static int epoll_dispatch(struct event_base *, struct timeval *);
static void epoll_dealloc(struct event_base *);
static int epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
    short old, short events, void *p);
static int epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
    short old, short events, void *p);

const struct eventop epollops = {
    "epoll",
    epoll_init,
    epoll_nochangelist_add,
    epoll_nochangelist_del,
    epoll_dispatch,
    epoll_dealloc,
    1, /* need reinit */
    EV_FEATURE_ET|EV_FEATURE_O1,
    0
};

2、evbase是void指针,它用来保存IO复用的数据,指向一个数据结构。因为Libevent是跨平台的,所以数据结构不定,因此是void类型指针。
3、struct event_changelist changelist;是上次调用eventop.dispatch之后,发生事件的event的集合,它是一个结构体。
4、evsigsel是专门处理信号的IO复用结构体。
5、activequeues是指向event_list的数组,它包含着已经发生的事件,需要调用这些事件的回调函数,事件有优先级。nactivequeues指明event_list数组的长度。
6、common_timeout_queues是一个二级指针,包含超时事件,它指向超时时间的数组。
7、io、sigmap用来存储IO事件和signal事件,未必是map。
8、eventqueue存储注册到当前event_base中的event。
9、timeheap是一个小根堆,用来管理定时事件。
10、th_notify_fd[2]用来唤醒当前event_base(可能等待在epoll_wait上)。

初始化event_base

event_base_new();

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);//用配置cfg初始化base
        event_config_free(cfg);
    }
    return base;
}

再来看一下event_base_new_with_config。在这个函数中,为event_base分配了内存,初始化其内部各个变量。

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_base分配空间
        event_warn("%s: calloc", __func__);
        return NULL;
    }
    detect_monotonic();
    //初始化base
    gettime(base, &base->event_tv);//获取当前时间

    min_heap_ctor(&base->timeheap);//初始化小根堆
    TAILQ_INIT(&base->eventqueue);//初始化事件队列
    //初始化与信号相关的Socketpair
    base->sig.ev_signal_pair[0] = -1;
    base->sig.ev_signal_pair[1] = -1;
    //Socketpair,用来唤醒当前线程
    base->th_notify_fd[0] = -1;
    base->th_notify_fd[1] = -1;

    event_deferred_cb_queue_init(&base->defer_queue);
    base->defer_queue.notify_fn = notify_base_cbq_callback;
    base->defer_queue.notify_arg = base;
    if (cfg)
        base->flags = cfg->flags;

    evmap_io_initmap(&base->io);
    evmap_signal_initmap(&base->sigmap);
    event_changelist_init(&base->changelist);

    base->evbase = NULL;

    should_check_environment =
        !(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));

    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];//给多路IO复用赋值

        base->evbase = base->evsel->init(base);//选择和多路IO复用对应的数据结
    }

    if (base->evbase == NULL) {
        event_warnx("%s: no event mechanism available",
            __func__);
        base->evsel = NULL;
        event_base_free(base);//event是在堆上开辟的内存,使用完后要释放
        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 */

#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,
            EVTHREAD_LOCKTYPE_RECURSIVE);
        base->defer_queue.lock = base->th_base_lock;
        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


    return (base);
}

相关接口

1、把event和event_base关联起来。成功返回0,失败返回-1。

int event_base_set(struct event_base *, struct event *);

即设置event->ev_base=event_base,还会设置event的优先级为event_base的1/2。

2、
将event添加到event_base(event->ev_base)中。tv为超时时间,如果不为NULL,还会添加到小根堆中。成功返回0,失败返回-1。

int event_add(struct event *ev, const struct timeval *tv)

3、将event移除event_base(event->ev_base)。成功 返回0,失败返回-1。

int event_del(struct event *ev)

4、分发事件,进入event_base循环

int event_base_dispatch(struct event_base *event_base)

版权声明:本文为博主原创文章,未经博主允许不得转载。

Libevent源码分析-event_base

标签:libevent   event-base   reactor   

原文地址:http://blog.csdn.net/kangroger/article/details/47761007

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!