Libev源码解析

2023-05-16

最近在看libev源码,算是对libev的源码有个比较清晰的了解。

总共分3部分来介绍libev.

1 Libev是什么

Libev是基于Reactor模式的一个高性能,支持高并发的事件库。它本身不仅支持IO,timer(定时器),还支持signal, fork等。并且它短小精悍 ,并且C语言实现。

2. Libev重要的数据结构

只有了解并且熟悉了Libev的基本数据结构,才能更顺利的理解Libev怎么实现的事件库的。

基类ev_watcher

typedef struct ev_watcher {                                          
  int active; // 激活标志                                            
  int pending; // 等待事件数                                         
  int priority; //优先级                                             
  void* data;                                                        
  // 回调函数                                                        
  void (*cb)(struct ev_loop* loop, struct ev_watcher* w, int revent);
} ev_watcher;                                                       

ev_watcher_list

typedef struct ev_watcher_list {
  int active;
  int pending;
  int priority;
  void* data;
  void (*cb)(struct ev_loop* loop, struct ev_watcher_list* w, int revent);
  struct ev_watcher_list* next;
} ev_watcher_list;

ev_watcher_time
typedef double ev_tstamp;
typedef struct ev_watcher_time {
  int active; // 激活标志
  int pending; // 等待事件数
  int priority; //优先级
  void* data;
  // 回调函数
  void (*cb)(struct ev_loop* loop, struct ev_watcher_time* w, int revent);
  ev_tstamp at;
} ev_watcher_time;
ev_timer
typedef struct ev_timer {
  int active; // 激活标志
  int pending; // 等待事件数
  int priority; //优先级
  void* data;
  // 回调函数
  void (*cb)(struct ev_loop* loop, struct ev_watcher_time* w, int revent);
  ev_tstamp at; // 在"at"之后发生timeout事件
  ev_tstamp repeat; // 在"repeat"之后触发timeout事件,循环
} ev_timer;
ev_io
typedef struct ev_io {
  int active;
  int pending;
  int priority;
  void* data;
  void (*cb)(struct ev_loop *loop, struct ev_io *w,int revents);
  struct ev_watcher_list *next;
  int fd;// 文件描述符
  int events;// 事件類型
} ev_io;
typedef struct ev_signal {
  int active;
  int pending;
  int priority;
  void* data;
  void (*cb)(struct ev_loop *loop, struct ev_signal *w,int revents);
  struct ev_watcher_list *next;
  int signum;  // 信号量like SIGxxx

} ev_signal;
ev_prepare
/* invoked for each run of the mainloop, just before the blocking call */
/* you can still change events in any way you like */
/* revent EV_PREPARE */
typedef struct ev_prepare {
  int active;
  int pending;
  int priority;
  void* data;
  void (*cb)(struct ev_loop *loop, struct ev_prepare *w,int revents);
} ev_prepare;
ev_check
/* invoked for each run of the mainloop, just after the blocking call */
/* revent EV_CHECK */
typedef struct ev_check {
  int active;
  int pending;
  int priority;
  void* data;
  void (*cb)(struct ev_loop *loop, struct ev_check *w,int revents);
} ev_check;
ev_loop:
struct ev_loop {
  ev_tstamp ev_rt_now;
  #define ev_rt_now ((loop)->ev_rt_now)
  #define VAR(name,decl) decl;
  #include "ev_vars.h" // 包含众多成员
  #undef VAR
};
ev_loop的成员:
ev_tstamp now_floor; /* last time we refreshed rt_time */ 
ev_tstamp mn_now; // 当前单调时间,系统开机时间 
ev_tstamp rtmn_diff; // difference realtime - monotonic time 
unsigned int origflags;
int backend; //epoll 、 kqueue 、 poll 、 select 、 port 标记
int activecnt;// 激活事件总数
int backend_fd;// 对于 epoll, 为 epoll_create 返回的描述符 
int * fdchanges;// 事件队列
int fdchangemax;// 当前最大事件数 
int fdchangecnt;// 事件数
ANPENDING *pendings [NUMPRI];// 待处理队列
int pendingmax [NUMPRI];// 当前最大等待事件的数量 
int pendingcnt [NUMPRI];// 记录每个优先级的数量

ANFD:

typedef struct{
  ev_watcher_list* head; //监听者链表
  unsigned char events; //监听的事件
  unsigned char reify;//状态位 用来表示具体是EV_ANFD_REIFY还是EV_IOFDSET
  unsigned char emask;//epoll用来保存内核mask的值
  unsigned char unused;//同名字
#if EV_USE_EPOLL
  unsigned int egen;//
#endif
#if EV_SELECT_ISWINSOCKET || EV_USE_IOCP
  SOCKET handle;//
#endif
#if EV_USE_IOCP
  OVERLAPPED or,ow;//
#endif
} ANFD;
ANPENDING
typedef struct {
  ev_watcher* w;
  int events;
} ANPENDING;
堆结构的节点(用于管理定时器)
typedef struct {
  ev_tstamp at;
  ev_watcher_time* w;
} ANHE;
开始前准备:

ev_init(ev_TYPE *watcher, callback

ev_set_priority(ev_TYPE*watcher, int priority)设置优先级

ev_io_init(ev_io *, callback, int fd, int events)

Fd:  EV_READ, EV_WRITEor EV_READ | EV_WRITE

ev_io_set(ev_io *, int fd, int events)

ev_timer_init(ev_timer *, callback, ev_tstamp after, ev_tstamp repeat)

ev_timer_set(ev_timer *, ev_tstamp after, ev_tstamp repeat)


3. ev_run执行流程

下图为ev_run的具体流程
backend_poll(epoll_poll)过程,是通过epoll_wait讲IO事件放入pendings数组里。下图为backend_poll的具体过程:
epoll_poll之后,将事件从anfds中找到对应的ANFD。
anfds, fdchanges和fd的关系如下图:
然后再取ANFD中的watcher,最后将watcher和发生的事件赋值给结构体ANPENDING,最后将ANPENDING按照优先级放入二维数组pendings中。
fd,andfs,pendings之间的关系如下:
上图表示,通过backend_poll函数中调用fd_event/fd_event_nocheck将epoll_wait之后拿到就绪fd,在用fd作为下标的anfds中查询,得到ANFD,之后通过ev_feed_event函数将watcher,event组成结构体ANPENDING,插入到pendings数组中。

通过epoll_poll之后,已经将就绪的IO事件放入pendings数组中,随后需要放入的是最小堆中的超时watcher。超时watcher放入过程如下:


在处理最小堆的watcher时,会先讲watcher放入rfeeds数组中,随后再逆序从rfeed中事件放入pendings数组中。这两个数组的关系如下:


在收集完所有的watcher之后,进入EV_INVOKE_PENDING的流程中,也就是从pendings数组中按照优先级顺序从数组中逆序去除watcher进行invoke_cb的回调。

具体过程如下:


其中pending数组和EV_INVOKE_PEINDING的过程关系图如下:



4  参考文献:

http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.podlibev官方文档)
http://blog.chinaunix.net/uid-8048969-id-5008922.html(事件库libev)



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

Libev源码解析 的相关文章

  • Spring源码解析3-beanFactoryPostProcessor的执行

    refresh 中的invokeBeanFactoryPostProcessors beanFactory invokeBeanFactoryPostProcessors xff0c 实例化并且调用所有已经注册了的beanFactoryPo
  • Spring Security 解析(七) —— Spring Security Oauth2 源码解析

    在学习Spring Cloud 时 xff0c 遇到了授权服务oauth 相关内容时 xff0c 总是一知半解 xff0c 因此决定先把Spring Security Spring Security Oauth2 等权限 认证相关的内容 原
  • FREERTOS源码解析——heap4.c

    目录 内存管理heap4无法解决的内存碎片 xff1a HEAP4简析分配内存在哪 xff0c 大小多少如何管理 重要源码解析 内存管理 freertos目前提供了以下5种内存管理 xff0c 特点如下 heap1 xff1a 最简单的内存
  • GVINS源码解析

    GVINS是基于VINS MONO写的 xff0c 视觉 IMU部分与VINS MONO类似 xff0c 可参考我的前一篇文章VINS MONO学习 这篇文章主要解析与GNSS有关的部分 持续更新中 文章目录 estimator node
  • BLAM源码解析(四)—— 基于ICP的位姿更新

    第三节我们介绍了定时器的定时回调 xff0c 实现对激光数据的批量循环处理 xff0c 在每一个激光数据的循环当中 xff0c 除了一开始filter 的点云过滤 xff0c 最重要的其实是下面的基于ICP的位姿更新 xff0c 即 if
  • Volley源码解析

    概述 本文基于Volley 1 1 1版本的源码 Volley是Google官方出的一套小而巧的异步请求库 xff0c 该框架封装的扩展性很强 xff0c 支持HttpClient HttpUrlConnection xff0c 甚至支持O
  • Android-Handler源码解析-Looper

    成员变量 Log的TAG private static final String TAG 61 34 Looper 34 线程本地变量 xff0c 保证了每个线程仅有唯一的Looper对象 64 UnsupportedAppUsage st
  • Redux源码解析(部分)

    相信用过React的小伙伴对于Redux一定不陌生 xff0c A Predictable State Container for JS Apps xff0c 这是官方文档对于Redux的定义 xff0c 即一款适用于JS Apps的可预测
  • Axios源码解析(部分)

    从 Github 上把 Axios 项目的 master 分支拷贝到本地 xff0c 用编辑器打开项目目录 首先我们先解析一下整个 Axios 项目的一些关键的文件结构 对照项目的文件目录 xff0c 梳理一下其中的一些关键文件夹以及它的作
  • PX4源码解析(一):bootloader

    1 简介 阅读PX4的代码不能用裸机的思维去读 xff0c 不能一开始就去找main函数 xff0c PX4的代码运用了自己的OS xff1a Nuttx 本文的环境 xff1a 硬件 xff1a Holybro Pixhawk 4 FMU
  • Mybatis源码解析:Java泛型详解

    注意 xff1a 泛型的类型参数只能是类类型 xff0c 不能是基本属性类型 xff1b 不能对确切的泛型类型使用instanceof操作 如下面的操作是非法的 xff0c 编译时会出错 if ex num instanceof Gener
  • Libev源码解析

    最近在看libev源码 xff0c 算是对libev的源码有个比较清晰的了解 总共分3部分来介绍libev 1 Libev是什么 Libev是基于Reactor模式的一个高性能 xff0c 支持高并发的事件库 它本身不仅支持IO xff0c
  • freeRtos源码解析(二)–任务调度

    freeRtos源码解析 二 任务调度 一 启动任务调度器 启动任务调度器之后 xff0c CPU正式进入任务模式调度各任务 xff08 CPU在中断模式和任务模式之间不断轮转 xff09 freeRtos任务调度依赖于内核的三个中断 xf
  • java源码解析JavaParser

    package com bootdo jparser import java io File import java io FileNotFoundException import com github javaparser JavaPar
  • pomelo源码解析--新建项目(cli工具: pomelo)

    pomelo怎么新建项目 官方文档 1 安装pomelo 2 新建项目HelloWorld 我简单整理了下创建新项目关键步骤 xff1a 安装pomelo 方式一 xff1a npm install pomelo g 方式二 xff1a g
  • RTKlib源码解析:ppp和rtkpost中的周跳检测函数

    文章目录 前言detslp mwdetslp gfdetslp lldetslp dop 欢迎关注个人公众号 xff1a 导航员学习札记 前言 本文解析了RTKlib ppp c中两个周跳检测函数detslp mw和detslp gf xf
  • 对象池(连接池):commons-pool2源码解析:GenericObjectPool的returnObject方法解析

    为什么会有对象池 在实际的应用工程当中 存在一些被频繁使用的 创建或者销毁比较耗时 持有的资源也比较昂贵的一些对象 比如 数据库连接对象 线程对象 所以如果能够通过一种方式 把这类对象统一管理 让这类对象可以被循环利用的话 就可以减少很多系
  • 对象池(连接池):commons-pool2源码解析:GenericObjectPool的borrowObject方法

    为什么会有对象池 在实际的应用工程当中 存在一些被频繁使用的 创建或者销毁比较耗时 持有的资源也比较昂贵的一些对象 比如 数据库连接对象 线程对象 所以如果能够通过一种方式 把这类对象统一管理 让这类对象可以被循环利用的话 就可以减少很多系
  • libev学习系列之四:ev_loop事件循环

    libev学习系列之四 ev loop事件循环 版本说明 版本 作者 日期 备注 0 1 ZY 2019 5 31 初稿 目录 文章目录 libev学习系列之四 ev loop事件循环 版本说明 目录 一 前言 二 描述 三 例子 一 前言
  • libev学习系列之三:libev编译安装

    libev学习系列之三 libev编译安装 版本说明 版本 作者 日期 备注 0 1 ZY 2019 5 31 初稿 目录 文章目录 libev学习系列之三 libev编译安装 版本说明 目录 源码结构 正常编译 交叉编译 源码结构 4 2

随机推荐

  • 操作系统-基本概念

    操作系统 王道老师 第一章 目录 xff1a 1 操作系统概念 功能和目标 2 操作系统的特征 3 OS的发展和分类 4 OS的运行机制和体系结构 5 中断 6 系统调用 1 操作系统概念 功能和目标 1 1 操作系统概念 xff1a 操作
  • c的2个struct 互相引用的例子

    struct pool data s u char last u char end pool t next struct pool s pool data t d size t max pool t current 上面的2个struct中
  • Mac常用应用 brew list

    61 61 gt Formulae ca certificates gdbm go libidn2 mpdecimal python 64 3 10 readline wget delve gettext jsonschema libuni
  • Slack 消息回传

    Slack预留了回传接口 可以将报错 告警信息等回传到Slack频道里 https api slack com messaging webhooks
  • Postgres 最大连接数满了: remaining connection slots are reserved for non-replication superuser connections

    最近遇到链接pg数据库报错 xff1a remaining connection slots are reserved for non replication superuser connections 百度说 xff0c 是由于设置的最大
  • oracle游标:fetch和for循环游标

    1 fetch 显式的open close Declare Cursor cur Is Select xtwldm From xtm14 curRow cur Rowtype Begin Open Cur Loop Fetch cur In
  • .net {"已添加项。字典中的关键字:“**”所添加的关键字:“**”"}

    用户代码未处理 System ArgumentException HResult 61 2147024809 Message 61 已添加项 字典中的关键字 00 所添加的关键字 00 Source 61 mscorlib StackTra
  • docker: 为运行的container增加多个端口

    1 list all docker process and stop running container test01 docker ps a docker stop test01 2 commit the container docker
  • git prune, git remote prune, git fetch --prune 三者异同

    远程分支的3种状态 远程仓库确实存在分支dev本地版本库 xff08 git xff09 中的远程快照和远程分支建立联系的本地分支 git prune https git scm com docs git prune Prune all u
  • Jmeter_Non HTTP response code: java.net.SocketException

    error msg rc 61 span class hljs string 34 Non HTTP response code java net SocketException 34 span rm 61 span class hljs
  • SQL Server 数据库导入导出数据

    Data Micration between SQL Server Database 1 减少源数据库的导出数据 排除日志表数据 xff1a 日志表数据体积大且没有导出价值 精简掉备份表 xff1a 为了保证数据的安全 xff0c 一般会对
  • Windows设置本地DNS域名解析Hosts

    DNS Domain Name System 域名系统 xff1a 为了加快定位IP地址的速度 将域名映射进行层层缓存的系统 目的 xff1a 互联网通过IP xff08 10 223 146 45 xff09 定位浏览器建立连接 xff0
  • python 在linux中使用sqlite3

    python 在linux中使用sqlite3 如果出现如下错误 gt gt gt imp ort sqlite3 Traceback most recent call last File 34 lt stdin gt 34 line 1
  • Archlinux设置静态固定IP

    最近装了Archlinux xff0c 可是每次开机后 xff0c 设置的IP都没有了 xff0c 废了好大劲才搞定 xff0c 俗话说好记性不如烂笔头 xff0c 特意摘录下来 xff0c 已备后需 首先 ifconfig a 查看自己的
  • Archlinux开机自动执行自己所写程序

    为了让Archlinux开机自动执行自己所写程序 xff0c 需要使用rc local service系统服务 搞了好久 xff0c 终于弄成功了 特意记录下 xff0c 以备后需 第一步在 usr lib systemd system 目
  • 【详细】linux安装weblogic12c-附详细截图

    linux安装weblogic12c目录 环境配置jdk安装创建目录 xff0c 用户 xff0c 组修改hosts文件设置DISPLAY配置防火墙安装weblogic配置weblogic server环境配置nodemanager pro
  • python 中Dict 转 Json

    最近在公司需要写个小工具 xff0c 运用到的python xff0c 然后需要将Dict转成Json 之前遇到转换Json失败 xff0c 然后以为复杂的Entity结构 xff0c 不能用Json的库Json dump xff0c 进行
  • Zabbix监控

    由于本人工作职责的一部分 xff0c 需要用Zabbix监控 xff0c 所以在此贴一下Zabbix监控 实在觉得Zabbix监控做的太牛掰 xff0c 先打Tag xff0c 周末再来补全
  • 看完23岁的我在干嘛之后有感

    现在我已经25岁了 xff0c 先说我23岁的时候吧 xff0c 23岁我在干嘛 xff0c 刚上研究生 xff0c 好像貌似一切都挺顺的 xff0c 考研成功 xff0c 进入北京比较好的一所大学读计算机 xff1b 然后是和前任分手 x
  • Libev源码解析

    最近在看libev源码 xff0c 算是对libev的源码有个比较清晰的了解 总共分3部分来介绍libev 1 Libev是什么 Libev是基于Reactor模式的一个高性能 xff0c 支持高并发的事件库 它本身不仅支持IO xff0c