libevent源码学习-----时间管理

libevent监听的event有以下几种

  • 文件描述符/套接字,没有设定超时时长
  • 信号
  • 文件描述符/套接字,设定超时时长

对于时间,libevent内部的时间管理是通过最小堆实现的,原因如下

  • 既然某些fd有规定的超时时长,那么io多路复用函数就不能永久阻塞,需要设定一个超时时长(最后一个参数)
  • 用户在使用event_add设定的时间是相对于event_add调用的相对时间,这就导致所有具有超时时长的event什么时候超时是杂乱无章的,没办法为io函数设定某个时长

针对以上原因,libevent内部将所有的event超时时长全部转化为绝对时间,有以下几点好处

  • 可以对所有的超时时间进行排序,获得最早超时的那个event
  • 判断是否超时时只需和现有时间比较大小,不需要每次都进行相对时间的判断
  • 可以采用最小堆存储所有具有超时时间的event,如果堆顶event未超时,那么所有的event都不会超时,可以选择这个event的超时时长最为io函数的阻塞时间

使用绝对时间带来的麻烦是如果event是一个永久事件,那么当event被激活后仍然需要重新注册到base中,此时因为event的时间是绝对时间的缘故,不能够直接调用event_add_internal添加event,而是需要重新计算超时时间再添加,这就导致仍然需要在event中存储用户提供的超时时长,在重新添加之前计算绝对时间的超时时间

/*
 * event_add调用的内部函数,用于将event添加到base的注册队列中
 * 同时添加到相应的map中
 * 
 * 注意:这个函数不仅仅只由event_add调用,还有event_persist_closure调用
 * 由这个函数调用是因为当具有超时时间的event被激活后,需要先从base中的所有队列中删除
 * 然后重新计算超时时间,再重新添加到base中,所以又重新调用了这个函数
 * 
 * 注意:event不仅代表文件描述符,还有可能是信号的event,当是信号时,会递归
 * 调用两遍这个函数,第一遍调用时判断是信号则调用evsig_map_add函数,在这个函数中
 * 进行两步
 *   将信号event添加到base的信号map中
 *   调用evsigops的add函数,即调用evsig_add,这个函数中绑定内部信号处理函数,同时将socketpair的event
 *   添加到base中,使用event_add,也就是调用event_add_internal
 * 不过只会执行两遍,因为在evsig_add中会进行判断,只有第一次添加socketpair的event时才会执行第二次调用
 * 
 * 见evsig_add
 */
static inline int
event_add_internal(struct event *ev, const struct timeval *tv,
    int tv_is_absolute)
{
    struct event_base *base = ev->ev_base;
    int res = 0;
    int notify = 0;

    EVENT_BASE_ASSERT_LOCKED(base);
    /* ... */

    /*
     * prepare for timeout insertion further below, if we get a
     * failure on any step, we should not change any state.
     */
    /*
     * 这一步主要是用来让最小堆增加一个位置,并没有实际添加到最小堆上
     * 判断条件是这是一个具有超时时间的event,同时在最小堆中没有这个event
     * 这样就需要在最小堆上留出一个位置来存放这个event
     * 因为用户可以对同一个event调用event_add多次,这就可能两次event_add除了超时时间不同
     * 其他的都相同,这样就不需要在留出一个位置,直接替换以前的就可以
     * 
     * 如果已经在最小堆中,ev_flags将是EVLIST_TIMEOUT
     */
    if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
        if (min_heap_reserve(&base->timeheap,
            1 + min_heap_size(&base->timeheap)) == -1)
            return (-1);  /* ENOMEM == errno */
    }



    /*
     * we should change the timeout state
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值