Libevent源码分析—event_add()

接下来就是将已经初始化的event注册到libevent的事件链表上,通过event_add()来实现,源码位于event.c中。

event_add()

这个函数主要完成了下面几件事:
1.将event注册到event_base的I/O多路复用要监听的事件中
2.将event注册到event_base的已注册事件链表中
3.如果传入了超时时间,则删除旧的超时时间,重新设置,并将event添加到event_base的小根堆中;
   如果没有传入超时时间,则不会添加到小根堆中。
只有步骤1成功,才会执行步骤2和3;否则什么都没做,直接返回,保证不会改变event的状态。
 
从中还可以看到,将event添加到已注册事件链表、添加到小根堆、从活跃事件链表移除、从小根堆中移除,都是通过两个函数完成的:event_queue_insert()、event_queue_remove()
int
event_add(struct event *ev, const struct timeval *tv)
{
    struct event_base *base = ev->ev_base;    //event所属的event_base
    const struct eventop *evsel = base->evsel;    //event_base的I/O多路复用机制
    void *evbase = base->evbase;    //event_base的I/O多路复用机制
    int res = 0;
    //DEBUG log.h
    event_debug((
         "event_add: event: %p, %s%s%scall %p",
         ev,
         ev->ev_events & EV_READ ? "EV_READ " : " ",
         ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
         tv ? "EV_TIMEOUT " : " ",
         ev->ev_callback));
    assert(!(ev->ev_flags & ~EVLIST_ALL));
    /*
     * prepare for timeout insertion further below, if we get a
     * failure on any step, we should not change any state.
     */
    //如果传入了超时时间并且event不再time小根堆上,则在小根堆上预留一个位置
    //以保证如果后面有步骤失败,不会改变初始状态,保证是个原子操作
    if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
        if (min_heap_reserve(&base->timeheap,    //min_heap.h
            1 + min_heap_size(&base->timeheap)) == -1)
            return (-1);  /* ENOMEM == errno */
    }
    //如果event不在已注册链表或活跃链表中,
    //则调用evsel->add()注册event事件到I/O多路复用监听的事件上
    if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
        !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
        res = evsel->add(evbase, ev);    //将event注册到监听事件上
        //注册监听事件成功,则将event注册到已注册事件链表上
        if (res != -1)
            event_queue_insert(base, ev, EVLIST_INSERTED);  //插入  
    }
    /* 
     * we should change the timout state only if the previous event
     * addition succeeded.
     */
    //前面操作都成功情况下,才能执行下面步骤
    //改变超时状态
    if (res != -1 && tv != NULL) {
        struct timeval now;
        /* 
         * we already reserved memory above for the case where we
         * are not replacing an exisiting timeout.
         */
        //EVLIST_TIMEOUT表明event已在定时器堆中
        //则删除旧的定时器
        if (ev->ev_flags & EVLIST_TIMEOUT)
            event_queue_remove(base, ev, EVLIST_TIMEOUT);  //移除
        /* Check if it is active due to a timeout.  Rescheduling
         * this timeout before the callback can be executed
         * removes it from the active list. */
        //如果事件是由于超时而变成活跃事件
        //则从活跃事件链表中删除
        if ((ev->ev_flags & EVLIST_ACTIVE) &&
            (ev->ev_res & EV_TIMEOUT)) {
            /* See if we are just active executing this
             * event in a loop
             */
            if (ev->ev_ncalls && ev->ev_pncalls) {
                /* Abort loop */
                *ev->ev_pncalls = 0;  //调用次数清0
            }
            //从活跃事件链表移除
            event_queue_remove(base, ev, EVLIST_ACTIVE);  //移除
        }
        gettime(base, &now);
        evutil_timeradd(&now, tv, &ev->ev_timeout);    //为event添加超时时间
        event_debug((
             "event_add: timeout in %ld seconds, call %p",
             tv->tv_sec, ev->ev_callback));
        //将event插入到小根堆中
        event_queue_insert(base, ev, EVLIST_TIMEOUT);  //插入
    }
    return (res);
}

event_queue_insert()

该函数根据不同的输入队列,即不同的事件,在不同的队列中插入,并增加相应的事件计数,更新event状态;
EVLIST_INSERTED:在已注册事件链表event_base.eventqueue插入
EVLIST_ACTIVE:根据event优先级,在活跃事件链表event_base.activequeues[event.ev_pri]插入
EVLIST_TIMEOUT:在小根堆event_base.timeheap中插入
void
event_queue_insert(struct event_base *base, struct event *ev, int queue)
{
    //如果event已经在活跃链表中,则返回;否则,出错
    if (ev->ev_flags & queue) {
        /* Double insertion is possible for active events */
        if (queue & EVLIST_ACTIVE)
            return;
        event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,
               ev, ev->ev_fd, queue);
    }
    if (~ev->ev_flags & EVLIST_INTERNAL)
        base->event_count++;  //增加注册事件数
    ev->ev_flags |= queue;  //改变event状态
    switch (queue) {  //根据不同的输入参数队列,选择在不同的事件集合中插入
    case EVLIST_INSERTED:  //I/O或Signal事件
        TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);  //在已注册事件链表插入
        break;
    case EVLIST_ACTIVE:  //活跃事件
        base->event_count_active++;  //增加活跃事件数
        TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],  //在活跃事件链表插入
            ev,ev_active_next);
        break;
    case EVLIST_TIMEOUT: {  //定时器事件
        min_heap_push(&base->timeheap, ev);  //在小根堆插入
        break;
    }
    default:
        event_errx(1, "%s: unknown queue %x", __func__, queue);
    }
}

event_queue_remove()

和event_queue_insert()相对应,这个函数主要根据不同的输入参数,从不同的事件集合中删除事件。
void
event_queue_remove(struct event_base *base, struct event *ev, int queue)
{
    if (!(ev->ev_flags & queue))
        event_errx(1, "%s: %p(fd %d) not on queue %x", __func__,
               ev, ev->ev_fd, queue);
    if (~ev->ev_flags & EVLIST_INTERNAL)
        base->event_count--;
    ev->ev_flags &= ~queue;
    switch (queue) {
    case EVLIST_INSERTED:  //I/O、Signal事件
        TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
        break;
    case EVLIST_ACTIVE:  //活跃事件
        base->event_count_active--;
        TAILQ_REMOVE(base->activequeues[ev->ev_pri],
            ev, ev_active_next);
        break;
    case EVLIST_TIMEOUT:  //定时器事件
        min_heap_erase(&base->timeheap, ev);
        break;
    default:
        event_errx(1, "%s: unknown queue %x", __func__, queue);
    }
}

event_del()

libevent还提供了event_del()这个函数,该函数从直接删除event事件,该函数就是主要通过调用event_queue_remove()函数完成删除的功能。
另外,该函数还将event从I/O多路复用监听的事件中删除。
int
event_del(struct event *ev)
{
    struct event_base *base;
    const struct eventop *evsel;
    void *evbase;
    event_debug(("event_del: %p, callback %p",
         ev, ev->ev_callback));
    /* An event without a base has not been added */
    if (ev->ev_base == NULL)
        return (-1);
    base = ev->ev_base;
    evsel = base->evsel;
    evbase = base->evbase;
    assert(!(ev->ev_flags & ~EVLIST_ALL));
    /* See if we are just active executing this event in a loop */
    //计数清0
    if (ev->ev_ncalls && ev->ev_pncalls) {
        /* Abort loop */
        *ev->ev_pncalls = 0;
    }
    //根据event不同的状态,从相应的event集合中删除
    if (ev->ev_flags & EVLIST_TIMEOUT)
        event_queue_remove(base, ev, EVLIST_TIMEOUT);
    if (ev->ev_flags & EVLIST_ACTIVE)
        event_queue_remove(base, ev, EVLIST_ACTIVE);
    if (ev->ev_flags & EVLIST_INSERTED) {
        event_queue_remove(base, ev, EVLIST_INSERTED);
        return (evsel->del(evbase, ev));  //从I/O多路复用监听的事件中删除
    }
    return (0);
}

 

 

转载于:https://www.cnblogs.com/zxiner/p/6929108.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值