libevent源码剖析-事件主循环

事件主循环主要是通过event_base_loop()函数完成的
event_base_loop所执行的循环
开始
第一步:(校正系统时间)

第二步:(根据timer heap的最小超时时间计算系统I/O多路复用的最大等待时间)

第三步:(更新last waittime,并清空time cache)

第四步:(调用系统I/O 多路复用等待就绪I/O events)

第五步:(检查signal的激活标记,如果被设置就检查激活信号事件(signal event),并把event插入到激活链表中)

第六步:(将就绪的I/O event插入到激活链表中)

第七步:(检查heap中的timer events,将就绪的timer event从heap上删除,并插入到激活链表中)

第八步:(根据优先级处理激活链表中的就绪event,调用其回调函数执行事件处理)
结束


int event_base_loop(struct event_base *base, int flags)
{
    const struct eventop *evsel = base->evsel;
    struct timeval tv;
    struct timeval *tv_p;
    int res, done, retval = 0;

    /* Grab the lock.  We will release it inside evsel.dispatch, and again
     * as we invoke user callbacks. */
    EVBASE_ACQUIRE_LOCK(base, th_base_lock);

    if (base->running_loop) {
        event_warnx("%s: reentrant invocation.  Only one event_base_loop"
            " can run on each event_base at once.", __func__);
        EVBASE_RELEASE_LOCK(base, th_base_lock);
        return -1;
    }

    base->running_loop = 1;//每个libevent创建的event_base只准执行一个event_base_loop

    clear_time_cache(base);//清空base的时间

    if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)
        evsig_set_base(base);

    done = 0;

#ifndef _EVENT_DISABLE_THREAD_SUPPORT
    base->th_owner_id = EVTHREAD_GET_ID();
#endif

    base->event_gotterm = base->event_break = 0;

    while (!done) {//开启循环
        base->event_continue = 0;

        /* Terminate the loop if we have been asked to */
        if (base->event_gotterm) {
            break;
        }//如果被要求中断我们就停止

        if (base->event_break) {
            break;
        }
        timeout_correct(base, &tv);

        tv_p = &tv;
        if (!N_ACTIVE_CALLBACKS(base) && !(flags & EVLOOP_NONBLOCK)) {
            timeout_next(base, &tv_p);
        } else {
            /*
             * if we have active events, we just poll new events
             * without waiting.
             */
            evutil_timerclear(&tv);
        }

        /* If we have no events, we just exit */
        if (!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
            event_debug(("%s: no events registered.", __func__));
            retval = 1;
            goto done;
        }

        /* update last old time */
        gettime(base, &base->event_tv);

        clear_time_cache(base);

        res = evsel->dispatch(base, tv_p);

        if (res == -1) {
            event_debug(("%s: dispatch returned unsuccessfully.",
                __func__));
            retval = -1;
            goto done;
        }

        update_time_cache(base);

        timeout_process(base);

        if (N_ACTIVE_CALLBACKS(base)) {
            int n = event_process_active(base);
            if ((flags & EVLOOP_ONCE)
                && N_ACTIVE_CALLBACKS(base) == 0
                && n != 0)
                done = 1;
        } else if (flags & EVLOOP_NONBLOCK)
            done = 1;
    }
    event_debug(("%s: asked to terminate loop.", __func__));

done:
    clear_time_cache(base);
    base->running_loop = 0;

    EVBASE_RELEASE_LOCK(base, th_base_lock);

    return (retval);
}

关于libevent库中I/O和Timer事件的统一
原因:
首先将Timer事件融合到系统I/O多路复用机制中还是相当清晰的,因为系统的I/O机制像select()和epoll_wait()都允许程序制定一个最大等待时间timeout,
即使没有I/O事件发生,它们也保证能在timeout时间内返回。
将Timer时间融合到系统I/O机制的方法:
根据所有Timer事件的最小超时时间来设置I/O的timeout时间;当系统I/O返回时,再激活所有就绪的Timer事件就可以了。
工具
libevent采用的是堆结构来管理Timer事件,因为他插入删除的时间复杂度都是O(lgN),N为堆元素个数而获取最小key值的复杂度为O(1),因此变成了管理Timer的绝佳人选

I/O和Signal事件的统一
将Signal融合到系统I/O机制的方法:
因为Signal的出现时随机的,所以如果当Signal发生时,我们并不立即调用event的callback函数处理信号,而是设法通知系统的I/O函数让其返回,然后再同一和I/O事件以及Timer一起处理就可以了,这也是libevent使用的方法。
问题的核心:
当信号发生时,如何通知I/O多路复用机智,可以使用管道,其余的信号详讲。(我觉得如果是线程的话能不能用线程的条件变量)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值