Libevent 事件循环(1)

2023-11-07

// 事件的dispatch 
int
event_base_loop(struct event_base *base, int flags) {
    //得到采用的事件模型 epoll/epoll/select 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);
    //判断是否loop正在running 如果由则退出 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;     //清理时间缓存 clear_time_cache(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     //终止和中断标志至0 base->event_gotterm = base->event_break = 0;     //事件循环 与 平时我们自己写的epoll_wait select 等待事件一样 在一个死循环中 while (!done) { base->event_continue = 0; base->n_deferreds_queued = 0; /* Terminate the loop if we have been asked to */
        //被其他线程中断 if (base->event_gotterm) { break
; } if (base->event_break) { break; } tv_p = &tv;
        //当前没有激活的事件
if (!N_ACTIVE_CALLBACKS(base) && !(flags & EVLOOP_NONBLOCK)) { timeout_next(base, &tv_p);//判断小根堆中的root是否已经超时, 如果超时 就将tv清0.  如果没有的话就将root的时间减去现在时间的结果赋值给tv(定时器触发的剩余
的时间长度)
} else { /* * if we have active events, we just poll new events * without waiting. */
            //如果有激活事件 就将tv清空 evutil_timerclear(&tv)
; } /* If we have no events, we just exit */
        //未注册事件就退出循环 if (
0==(flags&EVLOOP_NO_EXIT_ON_EMPTY) && !event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) { event_debug(("%s: no events registered.", __func__)); retval = 1; goto done; }          event_queue_make_later_events_active(base);         //清理时间缓存 clear_time_cache(base);         // 调用模型的epoll_wait/select/poll 等   tv_p 是刚才计算的最小时间间隔 res = evsel->dispatch(base, tv_p); //以epoll 为例详细说明 if (res == -1) { event_debug(("%s: dispatch returned unsuccessfully.", __func__)); retval = -1; goto done; }         //更新base中的时间, 下面就是调用定时事件和IO事件。 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); }

以 epoll 模型的dispatch 看一下evsel->dispatch(base, tv_p);

static int
epoll_dispatch(struct event_base *base, struct timeval *tv)
{
    struct epollop *epollop = base->evbase;
    struct epoll_event *events = epollop->events;
    int i, res;
    long timeout = -1;
    if (tv != NULL) {
        timeout = evutil_tv_to_msec_(tv); //将tv 话为 msec传递给epoll_wait
        if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) {
            /* Linux kernels can wait forever if the timeout is
             * too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */
            timeout = MAX_EPOLL_TIMEOUT_MSEC;
        }
    }

    epoll_apply_changes(base);
    event_changelist_remove_all_(&base->changelist, base);

    EVBASE_RELEASE_LOCK(base, th_base_lock);//多线程下防止惊群而加锁

    res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);//等待事件

    EVBASE_ACQUIRE_LOCK(base, th_base_lock);

    if (res == -1) {
        if (errno != EINTR) {
            event_warn("epoll_wait");
            return (-1);
        }
        return (0);
    }

    event_debug(("%s: epoll_wait reports %d", __func__, res));
    EVUTIL_ASSERT(res <= epollop->nevents);
    //依次处理事件
    for (i = 0; i < res; i++) {
        int what = events[i].events;
        short ev = 0;

        if (what & (EPOLLHUP|EPOLLERR)) {
            ev = EV_READ | EV_WRITE;
        } else {
            if (what & EPOLLIN)
                ev |= EV_READ;
            if (what & EPOLLOUT)
                ev |= EV_WRITE;
            if (what & EPOLLRDHUP)
                ev |= EV_CLOSED;
        }

        if (!ev)
            continue;
        //根据fd找到相应的位置  将event_callback加入到激活queue等待被调用
        evmap_io_active_(base, events[i].data.fd, ev | EV_ET);
    }
    // 拓展事件容量
    if (res == epollop->nevents && epollop->nevents < MAX_NEVENT) {
        /* We used all of the event space this time.  We should
           be ready for more events next time. */
        int new_nevents = epollop->nevents * 2;
        struct epoll_event *new_events;

        new_events = mm_realloc(epollop->events,
            new_nevents * sizeof(struct epoll_event));
        if (new_events) {
            epollop->events = new_events;
            epollop->nevents = new_nevents;
        }
    }

    return (0);
}

再看一下timeout_process.

static void
timeout_process(struct event_base *base)
{
    /* Caller must hold lock. */
    struct timeval now;
    struct event *ev;
    //没有定时事件直接退出
    if (min_heap_empty_(&base->timeheap)) {
        return;
    }

    gettime(base, &now);
    //取堆顶最小
    while ((ev = min_heap_top_(&base->timeheap))) {
         //没有超时就直接退出
if (evutil_timercmp(&ev->ev_timeout, &now, >)) break; /* delete this event from the I/O queues */    
      //有超时事件发生就将事件从io中删除
event_del_nolock_(ev, EVENT_DEL_NOBLOCK); event_debug(("timeout_process: event: %p, call %p", ev, ev->ev_callback));
        //加入激活队列中   最终会调用  event_queue_insert_timeout,被激活的计时和IO都放在同一个queue中 event_active_nolock_(ev, EV_TIMEOUT,
1); } }

 

转载于:https://www.cnblogs.com/MaAce/p/7988192.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Libevent 事件循环(1) 的相关文章

  • 2020Ti电赛体会与经验

    2020Ti电赛体会与经验 写在前面 要想打好电赛 必须要提前做好充足的软硬件准备 要想打好电赛 必须做好一定的知识技能储备 要想打好电赛 必须有几个 降维打击 的高招 写在前面 2020年的Ti电赛我们选择的是E题 四天三夜的结果是可喜可
  • Caused by: org.apache.logging.log4j.LoggingException: log4j-slf4j-impl cannot be present with log4j

    Caused by org apache logging log4j LoggingException log4j slf4j impl cannot be present with log4j SpringBoot出现该错误 log4j冲
  • 如何在Word文档中粘贴漂亮的代码

    写该博客的背景 最近做毕业设计 在写论文的时候 需要粘贴一些核心的代码 但是直接从IDEA中粘过去的代码又显得十分乱 关键不美观 对于我这样一个追求完美的人 这肯定是不能达到我的满足的 经过百度之后 决定写该博客记录一下这个转变过程 步骤如
  • Android文件存储

    参考文章 https blog csdn net baidu 36385172 article details 79695308 https www jianshu com p a39bc4b3a1a6 内部存储 外部存储 Android系
  • stable diffusion webui中的sampler

    Stable Diffusion 采样器篇 知乎采样器 Stable Diffusion的webUI中 提供了大量的采样器供我们选择 例如Eular a Heum DDIM等 不同的采样器之间究竟有什么区别 在操作时又该如何进行选择 本文将
  • Linux基础——Framebuffer(应用层驱动lcd)

    Framebuffer 简介 Framebuffer的API函数 1 open函数 2 ioctl 函数 3 mmap 函数 编写函数操作 开发环境 韦东山Linux开发板 IMX6ULL PRO 开发板 简介 Framebuffer 是用
  • 正则表达式简要笔记

    昨天在给领导演示的时候发现需要替换文件 结果发现同事那机器上只有UltraEdit我还不太会用 淦 没找到正则替换的入口 结果不了了之 后来回来在自己电脑上试了试 发现自己想的正则也不太对 索性现在总结一下最基础 通用 重要的符号 剩下的就
  • Fiddler抓包基础使用(二)

    续上一篇文章 软件测试人员电脑需要安装的基础工具 可可爱爱的程序员的博客 CSDN博客 软件测试资料领取方式 1 Issue 可可爱爱的程序员 软件测试资料合集 GIT CODE 响应HTTP状态过滤规则 Hide success 202
  • Redis 经典面试题合集详解

    作者主页 欢迎来到我的技术博客 个人介绍 大家好 本人热衷于Java后端开发 欢迎来交流学习哦 如果文章对您有帮助 记得关注 点赞 收藏 评论 您的支持将是我创作的动力 让我们一起加油进步吧 文章目录 1 谈谈你对 Redis 的了解 2
  • Java基础——Object类和Objects工具类

    目录 1 Object类 1 1 常用方法 1 2 Object类中方法常见的问题 1 为什么重写equals时必须重写hashCode方法 2 wait和notify为什么定义在Object类当中 wait和notify或notifyAl
  • Brocade_porterrshowt(博科交换机端口状态分析)

    Brocade Switches 如何确定是SFP 或是光纤线导致 Loss of Link 丢失链接 问题 问题描述 一个有问题的SFP或光纤线会造成丢失与主机 存储或另一台交换机的连接问题 在交换机的error log中可能有如下显示
  • RPM包基本命令

    RPM包基本命令 原文链接 https www cnblogs com zqwang0929 p 3352237 htmls 例子 rpm ivh example rpm 安装 example rpm 包并在安装过程中显示正在安装的文件信息
  • python二级菜单_python二级登陆菜单

    1 三级菜单 注册 登陆 注销 2 进入每一个一级菜单 都会有下一级的菜单 user item dict try while True print Welcome sir input choice int input Please ente
  • 利用cordova打包apk

    声明 电脑未安装过android studio 不会使用android studio 在此基础上将vue cli3项目打包成apk 百度了一下如何将vue项目打包成apk 百度说用HBuilderX 10秒就可以完成 然后我就按照百度的方法
  • Bert CNN信息抽取

    Github参考代码 https github com Wangpeiyi9979 IE Bert CNN 数据集来源于百度2019语言与智能技术竞赛 在上述链接中提供下载方式 感谢作者提供的代码 1 信息抽取任务 给定schema约束集合
  • webpack 热更新原理解析

    一 什么是 HMR HMR 全称 Hot Module Replacement 中文语境通常翻译为模块热更新 它能够在保持页面状态的情况下动态替换资源模块 提供丝滑顺畅的 Web 页面开发体验 1 1 HMR 之前 在 HMR 之前 应用的
  • JavaScript HTML DOM - 改变CSS

    要使用JavaScript改变HTML元素的CSS样式 可以通过访问元素的style属性来实现 下面是一些常见的方法 1 直接设置样式属性 javascript var element document getElementById myE
  • VISIO,不规则封闭图形填充方法

    VISIO 不规则封闭图形填充方法 2013 01 17 11 42 08 分类 Windows平台 VISIO 不规则封闭图形颜色填充方法 使用VISIO 2010 时 对规则的封闭图形填充非常简单 但是要想画一个不规则的图形 并且填充颜
  • Whois原理

    RFC812 定义了一个非常简单的Internet信息查询协议 WHOIS协议 其基本内容是 先向服务器的TCP端口43建立一个连接 发送查询关 键字并加上回车换行 然后接收服务器的查询结果 世界上各级Internet管理机构秉承公开 公正
  • python字典(dictionary)

    字典 字典组成 字典由键 key 和值 value 组成 字典元素由 括在一起 dic key1 value1 key2 value2 key是字典中的键 value是该键对应的值 key value称之为键值对 字典的创建 直接按照定义创

随机推荐

  • 高校校园网络设计与实现

    这是我的第一个博客 好好学习 天天向上 一 设计目的 通过大型园区网的设计与方案设计 实习完成后学生将可以独立完成网络拓扑设计 网络设备调试 安装以及优化 通过项目的完成学生可以达到以下目标 1 掌握工程项目的流程设计及文档编写 2 掌握网
  • 无法正常访问服务器

    网络原因 本地网络 解决办法 检查本地网络是否正常 访问外网是否流畅 机房网络 通过路由追踪查看是否中间有 节点不通 确定是线路出现丢包 远程连接 检查远程连接是否启用以及远程计算机上的连接数是否超出 未启用和超出连接数都会出现服务器无法连
  • 如何更改conda环境位置

    参考Anaconda 安装及修改环境默认位置 把环境从C盘移动到D盘 首先 D conda envs是我的目标文件夹路径 在conda中输入命令 torch 04seaFusion D pythonProjects paper06 yolo
  • vue3安装vue3-json-viewer

    vue3安装vue3 json viewer 官方文档 效果图 安装 npm i vue3 json viewer 2 2 2 提醒 2 1 0以下版本需要依赖clipboard 2 1 0以上版本不需要依赖clipboard 使用
  • Python中元组的函数

    定义一个带字段名的元组 from collections import namedtuple User namedtuple User name sex age user User lisi male 12 print user User
  • CentOS7查找目录或文件

    which命令 查找用户所执行的命令文件存放的目录 which命令用于查找Linux命令程序并显示所在的具体位置 其搜索范围主要由用户的环境变量PATH决定 可以执行 echo PATH 命令查看 这个范围也是Linux系统在执行命令或程序
  • 复旦nlp实验室 nlp-beginner 任务四:基于LSTM+CRF的序列标注

    经历了期末摸鱼之后它终于来了 认认真真的学了CRF 先上个Demo版本 model import torch import torch nn as nn from torch nn utils rnn import pack padded
  • 面试中关于Redis的问题看这篇就够了

    昨天写了一篇自己搭建redis集群并在自己项目中使用的文章 今天早上看别人写的面经发现redis在面试中还是比较常问的 笔主主Java方向 所以查阅官方文档以及他人造好的轮子 总结了一些redis面试和学习中你必须掌握的问题 事无巨细 不可
  • ILRuntime学习——从零开始

    1 ILRuntime项目为基于C 的平台 例如Unity 提供了一个纯C 实现 快速 方便且可靠的IL运行时 使得能够在不支持JIT的硬件环境 如iOS 能够实现代码的热更新 2 无缝访问C 工程的现成代码 无需额外抽象脚本API 推荐的
  • vue组件化(三)父子之间的访问和slot插槽相关知识

    children和 ref 父组件访问子组件使用 children或 ref this children时一个数组类型 它包含所有子组件对象 我们通过遍历可以取出所有子组件的状态 不常用 ref比较像getElemengtById 可以直接
  • 前端项目实战218-ant design table单元格编辑

    import React useState useEffect from react import Form Input InputNumber Popconfirm Table Typography message DatePicker
  • 软件工程python就业方向-软件工程实践总结

    软工ByeBye 请回望暑假时的第一次作业 你对于软件工程课程的想象 对比开篇博客你对课程目标和期待 希望通过实践锻炼 增强计算机专业的能力和就业竞争力 对比目前的所学所练所得 在哪些方面达到了你的期待和目标 哪些方面还存在哪些不足 为什么
  • The OpenGL® Shading Language, Version 4.60.7 翻译第一章

    The OpenGL Shading Language Version 4 60 7 翻译第一章 Chapter 1 Introduction This document specifies only version 4 60 of the
  • skimage的简介

    skimage的简介 skimage即是Scikit Image 基于python脚本语言开发的数字图片处理包 比如PIL Pillow opencv scikit image等 PIL和Pillow只提供最基础的数字图像处理 功能有限 o
  • activiti 自定义函数解析juel表达式

    activiti是支持juel表达式的 这个也很好用 但实际过程中需要支持类方法及变量 原来项目中解析juel 这边有自定义一个方法的 代码如下 public String getStringByELAndFormData String e
  • 使用C语言编写Python扩展1——Hello World

    使用C语言编写Python扩展1 Hello World 时间 2014 04 12 18 01 10 龍昌博客 原文 http www xefan com archives 84082 html 主题 Python C语言 能够使用C语言
  • 设计模式复习之装饰器模式

    一 装饰器模式 摘录 装饰器模式又称为包装 Wrapper 模式 装饰器模式以多客户端透明的方式扩展对象的功能 是继承关系的一个替代方案 通常给对象添加功能 要么直接修改对象添加相应的功能 要么派生子类来扩展 抑或是使用对象组合的方式 显然
  • 如何用Python创建SQL数据库 ? 学会就非常完美~

    今日份知识你摄入了么 会写SQL很重要 能高效地查询数据库被认为是数据分析师 科学家最基本的技能之一 SQL不仅重要 而且非常常用 根据 2021年Stackoverflow开发者调查 SQL是最常用的五种编程语言之一 所以 我们应该多投入
  • STL实现排序

    使用sort函数对容器内的随机元素进行排序 sort RandomAccessIterator first RandomAccessIterator last Compare comp RandomAccessIterator first
  • Libevent 事件循环(1)

    事件的dispatch int event base loop struct event base base int flags 得到采用的事件模型 epoll epoll select const struct eventop evsel