Libevent源码分析-event_base

前端之家收集整理的这篇文章主要介绍了Libevent源码分析-event_base前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

前面介绍了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,void *p);
static int epoll_nochangelist_del(struct event_base *base,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);
}

event_base_init()

struct event_base *
event_init(void)
{
    struct event_base *base = event_base_new_with_config(NULL);

    if (base == NULL) {
        event_errx(1,"%s: Unable to construct event_base",__func__);
        return NULL;
    }

    current_base = base;

    return (base);
}

这个和event_base_new的区别为:1、使用的配置不同。2、设置了全局便来current_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)

猜你在找的React相关文章