zoukankan      html  css  js  c++  java
  • libevent2源码分析之二:初始化流程

    本文并不很详细地分析初始化的各个细节,而重点分析如何将底层操作关联到event_base的相关字段。初始化工作主要是针对event_base的。libevent2支持多种底层实现,有epoll, select, iocp等。下面的工作主要是以熟悉的select作为底层实现,分析libevent2的工作机理。

    event_base的结构片断如下:

    struct event_base {

        /** Function pointers and other data to describe this event_base's

         * backend. */

    /// 保存底层操作的抽象对象(实际上是IO操作)

        const struct eventop *evsel;

        /** Pointer to backend-specific data. */

    /// 保存底层操作对象要操作的对象

        void *evbase;

    ...

    }

     

    不管底层操作是 select 还是 epoll 还是其它。都被抽象成下面的几个操作: init, add, del, dispatch...

    struct eventop {

        const char *name;

        void *(*init)(struct event_base *);

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

        int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);

        int (*dispatch)(struct event_base *, struct timeval *);

        void (*dealloc)(struct event_base *);

        int need_reinit;

        enum event_method_feature features;

        size_t fdinfo_len;

    };

    基于 select 操作是如何初始化 const struct eventop *evsel 这个变量的?

    1. select.c 中定义了一个 eventop 类型的static变量。

    const struct eventop selectops = {

        "select",

        select_init,

        select_add,

        select_del,

        select_dispatch,

        select_dealloc,

        0, /* doesn't need reinit. */

        EV_FEATURE_FDS,

        0,

    };

    这样selectops的init就指向select_init, add指向select_add...

     

    2. 将selectops注册到 eventops 这个数组中,作为底层操作的一个选项。数组中,位于前面的数据具有优先选择权。可以看到,select作为一个不被推荐的方式放到了倒数第二的位置。但这并不妨碍我们使用select这个熟悉的方式来分析libevent2的运行机制。

    [event.c]

    /* Array of backends in order of preference. */

    static const struct eventop *eventops[] = {

    #ifdef _EVENT_HAVE_EVENT_PORTS

        &evportops,

    #endif

    #ifdef _EVENT_HAVE_WORKING_KQUEUE

        &kqops,

    #endif

    #ifdef _EVENT_HAVE_EPOLL

        &epollops,

    #endif

    #ifdef _EVENT_HAVE_DEVPOLL

        &devpollops,

    #endif

    #ifdef _EVENT_HAVE_POLL

        &pollops,

    #endif

    #ifdef _EVENT_HAVE_SELECT

        &selectops,

    #endif

    #ifdef WIN32

        &win32ops,

    #endif

        NULL

    };

     

    3. 那么在哪里将 eventops 给event_base.evsel 赋值呢?赋赋值操作的前面和后面做了些什么呢?

    这是在创建event_base做的事情。且看 event_base_new_with_config函数的实现。

    [event.c]

    struct event_base * event_base_new_with_config(const struct event_config *cfg)

    {

    ...

        for (i = 0; eventops[i] && !base->evbase; i++) {

    ...

            base->evsel = eventops[i];

            base->evbase = base->evsel->init(base);

        }

    ...

    }

    可见是将数组中的第1个有效的记录赋值给了 base->evsel, 作为底层的实现。同时调用了 init 函数,将返回的操作数据传递给了 base->evbase.

    event_base_new() 的内部调用了 event_base_new_with_config.

    再深入地跟踪一下 init 函数。看它做了些什么,返回了些什么。select 模型对应的 initselect_init.

    [select.c]

    static void *

    select_init(struct event_base *base)

    {

        struct selectop *sop;

        if (!(sop = mm_calloc(1, sizeof(struct selectop))))

            return (NULL);

        if (select_resize(sop, SELECT_ALLOC_SIZE(32 + 1))) {

            select_free_selectop(sop);

            return (NULL);

        }

     

        evsig_init(base);

        return (sop);

    }

     

    struct selectop {

        int event_fds;        /* Highest fd in fd set */

        int event_fdsz;

        int resize_out_sets;

        fd_set *event_readset_in;

        fd_set *event_writeset_in;

        fd_set *event_readset_out;

        fd_set *event_writeset_out;

    };

     

    可见初始化并返回了一个struct selectop类型的指针。一般的思路是通过 calloc(malloc类似)申请一段内存,再调用evsig_init初始化信号的底层实现。那么调用 select_resize 干什么呢?看一下 struct selectop的结构,后面的四个指针指向的内存还没有初始化呢,select_resize就是初始化这些指针,让它指向一个fd_set的数组。数组的大小是多少字节呢?这个由宏 SELECT_ALLOC_SIZE(32 + 1) 计算。这个宏的参数 32 + 1 即为数组的长度,根据select的规则,32为有效的长度。这些描述表明,读取队列的初始长度是32.

     

     

  • 相关阅读:
    关于自适应的矩形css布局
    关于在天机项目中遇到的常用git 命令
    关于es6中对象的扩展
    vue的钩子函数
    关于Javascript的forEach 和 map
    关于router-link的传参以及参数的传递
    关于vuex的项目中数据流动方式
    vue中关于prop
    提交Sublime Text 插件到Package Control
    写lua时需要注意的地方
  • 原文地址:https://www.cnblogs.com/qkhh/p/3679358.html
Copyright © 2011-2022 走看看