libevent源码分析之事件激活

本文详细探讨了libevent库的源码,重点关注事件激活的过程。通过分析关键函数和数据结构,揭示了libevent如何高效地管理和调度事件,以及在处理I/O和定时事件时的内部工作原理。
摘要由CSDN通过智能技术生成
之前了解过了多种事件, 但都是从是什么, 如何理解, 如何存储的方面讲解的, 这里就集中的谈谈事件的激活
了解的事件有, 基本IO事件, 信号事件, 超时事件(只是事件可以是单纯的超时事件, 也可以是其他事件带有定时器, 因此不会特意看超时事件)
以及不同优先级事件的处理

虽然IO事件与信号事件是截然不同的处理方式, 但他们的事件处理程序都是处测在同一个event_base中的, 所以想要了解如何处理这两种事件, 关注的点就是event_base的dispatch, 之后蔓延开来
无论是 event_base_dispatch() 还是 event_loop() 都是调用的event_base_loop()


注意:

整篇文章是以event_base_loop()为核心, 通过分析其中调用的函数来对整个执行过程进行全面的了解
所以, 但凡遇到函数了, 在文章后面部分都会对函数进行分析, 阅读方式是先对event_base_loop函数有个粗略的了解, 之后从头开始, 分析其中详细内容
分析之前, 我自身对其中几个地方是存在疑惑的, 比如线程,对于线程锁、条件变量的设计经常会卡住, 甚至一直搞不明白, 所以遇到锁,条件变量就跳过, 当作是单线程来看把

大纲:
//在event.c中, 这里面省略了些许不相关代码
int
event_base_loop(struct event_base *base, int flags)
{
    /* Grab the lock.  We will release it inside evsel.dispatch, and again
     * as we invoke user callbacks. */
        //获取锁, 且是在调用evsel->dispatch() 前释放的锁, 需要配合evsel->dispatch的多线程逻辑
    EVBASE_ACQUIRE_LOCK(base, th_base_lock);

        //一个base在一个时间段内只能被一个线程运行
    if (base->running_loop) {
        ... ...(error)
    }

        //如果在event_base_dispatch之前, 有对信号的event_add调用, 那么 base->sig.ev_signal_added就会为1
        //反之, 如果用户没有要求关注任何信号, 那么这个if就会被跳过了
        //这个函数的目的在于为libevent的信号模块设置全局变量, 比如指定接收信号的base是哪个, 要监听几个信号, IO复用中信号事件的管道一端是哪个
    if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)
        evsig_set_base(base);

    done = 0;


    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;
                //如果此时没有已经激活的事件需要处理(如果对这里有疑惑, 那么还请继续往下看, 先假设是第一次启动base), 并且base不是非阻塞的, 此时就要为base指定一个超时时间
                //timeout_next函数就是用来指定新的超时时间的, 看此函数下面的解析
        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 */
                //没有事件, 且没有激活事件,说明没有事情要base做,即可退出
        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);

                //这就是核心的IO复用函数调用, 就涉及我们要讨论的处理激活事件的过程
                //所以看到这里, 我希望可以转到evsel->dispatch函数中去了解其中的内容, 接着继续回到这里
                //概括性的来说, evsel->dispatch的目的是在得知有数据要来后, 将对应的文件描述符激活
        res = evsel->dispatch(base, tv_p);

        if (res == -1) {
            ... ...(error)
            goto done;
        }

        upd
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值