• Libevent源码分析—event_init()


    下面开始看初始化event_base结构的相关函数。相关源码位于event.c

    event_init()

    首先调用event_init()初始化event_base结构体
    struct event_base *
    event_init(void)
    {
        struct event_base *base = event_base_new();    //event_init()调用event_base_new()
        if (base != NULL)
            current_base = base;
        return (base);
    }

    我们发现event_init()工作量很少,只是调用event_base_new()函数,所以真正初始化event_base的工作是在event_base_new()函数内完成。

    event_base_new()

    struct event_base *
    event_base_new(void)    //初始化libevent的event_base
    {
        int i;
        struct event_base *base;
        if ((base = calloc(1, sizeof(struct event_base))) == NULL)    //在堆上分配内存存储event_base,所有字段初始化为0
            event_err(1, "%s: calloc", __func__);
        event_sigcb = NULL;
        event_gotsig = 0;
        detect_monotonic();    //设置use_monotonic变量
        gettime(base, &base->event_tv);    //base->tv_cache.tv_sec非0,则赋给base->event_tv
        
        min_heap_ctor(&base->timeheap);    //初始化定时事件的小根堆base->timeheap    min_heap.h
        TAILQ_INIT(&base->eventqueue);    //初始化注册事件链表base->eventqueue    sys/queue.h
        base->sig.ev_signal_pair[0] = -1;    //初始化信号base->sig
        base->sig.ev_signal_pair[1] = -1;
        
        base->evbase = NULL;    //初始化I/O多路复用 base->evbase
        //遍历全局数组eventops[],初始化libevent的I/O多路复用机制
        for (i = 0; eventops[i] && !base->evbase; i++) {    //以NULL标志数组结尾,只选取一个I/O多路复用机制
            base->evsel = eventops[i];    //初始化base->evsel
            base->evbase = base->evsel->init(base);    //初始化base->evbase
        }
        if (base->evbase == NULL)    //没有I/O多路复用
            event_errx(1, "%s: no event mechanism available", __func__);
        if (evutil_getenv("EVENT_SHOW_METHOD")) //调用getenv()获取环境变量EVENT_SHOW_METHOD    evutil.c
            event_msgx("libevent using: %s
    ",
                   base->evsel->name);
        /* allocate a single active event queue */
        //event_base_new()内调用event_base_priority_init()
        event_base_priority_init(base, 1);    //设置优先级base->nactivequeues;分配数组base->activequeues。数组大小和优先级相同
        return (base);
    }

    其中由3点需要注意:

    1.该函数调用calloc()在堆上分配内存来存储event_base;

    2.使用全局数组eventops[]存储系统支持的I/O多路复用机制,然后遍历该数组,选取第1个I/O多路复用机制。

    3.libevent支持event有优先级,所以又调用了event_base_priority_init()来完成优先级相关的设置。

    event_base_priority_init()

    //设置不同event的优先级,值越小,优先级越高
    //返回值:0,成功;-1,出错
    int
    event_base_priority_init(struct event_base *base, int npriorities)
    {
        int i;
        if (base->event_count_active)    //当前base上有活跃的events则不能设置优先级,返回。
            return (-1);
        if (npriorities == base->nactivequeues)    //设置的优先级和当前优先级相同,则直接返回
            return (0);
        if (base->nactivequeues) {    //不同,则先释放原先的activequeues数组
            for (i = 0; i < base->nactivequeues; ++i) {
                free(base->activequeues[i]);
            }
            free(base->activequeues);
        }
        /* Allocate our priority queues */
        base->nactivequeues = npriorities;    //设置新的优先级
        base->activequeues = (struct event_list **)
            calloc(base->nactivequeues, sizeof(struct event_list *));    //设置和优先级值相同大小的event_list数组
        if (base->activequeues == NULL)
            event_err(1, "%s: calloc", __func__);
        for (i = 0; i < base->nactivequeues; ++i) {
            base->activequeues[i] = malloc(sizeof(struct event_list));    //初始化activequeues数组中每个元素
            if (base->activequeues[i] == NULL)
                event_err(1, "%s: malloc", __func__);
            TAILQ_INIT(base->activequeues[i]);
        }
        return (0);
    }

    该函数设置优先级,初始化了event_base的nactivequeues成员和activequeues成员。优先级值越小,优先级越高。在活跃事件链表中,优先级高的event先被处理。

  • 相关阅读:
    内存碎片
    《大规模分布式存储系统》笔记——单机存储系统、分布式系统
    数据库的范式
    一把剪刀看懂git reset 和它的三个参数
    如何判断一个链表是否有环?以及对一些文章的错误的看法
    自由树的计数 Labeled unrooted tree counting
    C语言里的指针探析——type *name[] 在函数参数里面,是一个二维指针
    CSAPP(深入理解计算机系统)读后感
    VIM一些常用命令,方法,配置
    Latex 常用知识点存档
  • 原文地址:https://www.cnblogs.com/zxiner/p/6920061.html
Copyright © 2020-2023  润新知