libevent不仅支持io事件,同时还支持timeout事件与signal事件,这篇文件将分析libevent是如何组织timeout事件以及如何响应timeout事件。

1.  min_heap

首先,event_base中有一个成员struct min_heap timeheap,这是一个最小堆,用来存储timeout事件的结构之一。先来看一下它的定义:

typedef struct min_heap
{
struct event** p;
size_t n, a;
} min_heap_t;

p是一个可以动态扩展的指针数组,数组长度为a,n表示堆成员数量,堆成员是指向event结构的指针。libevent中最小堆相关的操作定义在minheap-internal.h源码文件中,使用这些操作可以维持数组中的成员保持最小堆性质。

堆排序的依据是event结构中的成员ev_timeout,这个成员记录了事件超时的绝对时间(即超时时间点)。根据最小堆性质,堆顶元素总是最早超时的事件。

2.  event_base_loop

使用min_heap的堆顶元素,libevent总是可以知道从现在起到有事件超时所需的时间tv,这个操作在event_base_loop中调用timeout_next函数完成。libevent处理io事件的后端接口,如select,都有一个时间参数作为阻塞的最长时间,将tv作为后端接口的入参,那么event_base_loop在循环中总是会在有事件超时之前被唤醒。唤醒后再循环检查min_heap的堆顶元素是否超时,超时则将它加入到event_base的待执行回调函数链表,这步操作在event_base_loop中调用timeout_process函数实现。如此即可实现超时事件的响应。

3.  common_timeout_queues

仅使用min_heap成员,event_base已经足够管理timeout事件了,但是当有太多的timeou事件时,维持最小堆性质会成为一个耗时的操作。为解决这个问题,libevent使用了一个叫做common_timeout_list的结构,将超时时间相近的事件放到一起,这些事件在min_heap中仅留一个代表,减少min_heap的成员数量。common_timeout_list结构的定义如下(源码在event-internal.h中):

struct common_timeout_list {
/* List of events currently waiting in the queue. */
struct event_list events;
/* 'magic' timeval used to indicate the duration of events in this
* queue. */
struct timeval duration;
/* Event that triggers whenever one of the events in the queue is
* ready to activate */
struct event timeout_event;
/* The event_base that this timeout list is part of */
struct event_base *base;
};

events是一个事件的双向链表,连接了所有属于这个common_timeout_list的超时事件,struct event结构中的成员ev_timeout_pos.ev_next_with_common_timeout正是用来构造这个链表;duration是一个带有特殊标记的时间戳(后面解释如何标记);timeout_event即是加入min_heap中的代表事件;base记录了归属的event_base结构。

event_base中可以存在多个common_timeout_lsit结构,它使用common_timeout_queues进行管理,这是一个动态扩展的指针数组,每一个成员都指向一个common_timeout_list结构,n_common_timeouts_allocated表示动态数组的长度,n_common_timeouts代表有效的成员数目,common_timeout_queues的结构可以用图3-1表示:

图3-1 common_timeout_queues结构

  • 首先,common_timeout_list中的事件是按超时时间顺序排列的
  • 然后,common_timout_lsit中有一个专职的事件timeout_event用来加入到min_heap中,它的超时时间是事件链表中最早的超时时间。timeout_event的回调函数也是特殊设计的,作用是遍历它归属的common_timeout_list上的事件链表,将超时的事件加入到event_base的待执行回调函数链表上。timeout_event的优先级被设置为0,在event_base_loop处理待执行回调函数时会优先执行,在它的回调函数中处理的超时事件加入的待执行回调函数链表优先级较低,因此这些事件的回调函数还可以在同一次event_base_loop循环中被执行。

类似timeout_event这种特殊事件被称为内部事件,类似的设计在libevent处理signal事件中也有用到。

common_timeout_list事件中timeval的特殊标记:

libevent设计了如下标记:

/** Mask used to get the real tv_usec value from a common timeout. */
#define COMMON_TIMEOUT_MICROSECONDS_MASK 0x000fffff
#define MICROSECONDS_MASK COMMON_TIMEOUT_MICROSECONDS_MASK
#define COMMON_TIMEOUT_IDX_MASK 0x0ff00000
#define COMMON_TIMEOUT_IDX_SHIFT 20
#define COMMON_TIMEOUT_MASK 0xf0000000
#define COMMON_TIMEOUT_MAGIC 0x50000000

所有common_timeout_list链表中的event的ev_timeout.tv_usec都会异或上值COMMON_TIMEOUT_MAGIC作为标识;并将这个common_timeout_lsit在common_timeout_queues数组中的索引记录在第21bit至28bit中;真正的tv_usec值只使用了COMMON_TIMEOUT_MICROSECONDS_MASK标记的比特位。

libevent源码分析二--timeout事件响应的更多相关文章

  1. libevent源码分析一--io事件响应

    这篇文章将分析libevent如何组织io事件,如何捕捉事件的发生并进行相应的响应.这里不会详细分析event与event_base的细节,仅描述io事件如何存储与如何响应. 1.  select l ...

  2. libevent源码分析三--signal事件响应

    libevent支持io事件,timeout事件,signal事件,这篇文件将分析libevent是如何组织signal事件,以及如何实现signal事件响应的. 1.  sigmap 类似于io事件 ...

  3. 【转】libevent源码分析

    libevent源码分析 转自:http://www.cnblogs.com/hustcat/archive/2010/08/31/1814022.html 这两天没事,看了一下Memcached和l ...

  4. Libevent源码分析 (1) hello-world

    Libevent源码分析 (1) hello-world ⑨月份接触了久闻大名的libevent,当时想读读源码,可是由于事情比较多一直没有时间,现在手头的东西基本告一段落了,我准备读读libeven ...

  5. [Abp vNext 源码分析] - 13. 本地事件总线与分布式事件总线 (Rabbit MQ)

    一.简要介绍 ABP vNext 封装了两种事件总线结构,第一种是 ABP vNext 自己实现的本地事件总线,这种事件总线无法跨项目发布和订阅.第二种则是分布式事件总线,ABP vNext 自己封装 ...

  6. 十、Spring之BeanFactory源码分析(二)

    Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...

  7. Tomcat源码分析二:先看看Tomcat的整体架构

    Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Conn ...

  8. Vue源码分析(二) : Vue实例挂载

    Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...

  9. 多线程之美8一 AbstractQueuedSynchronizer源码分析<二>

    目录 AQS的源码分析 该篇主要分析AQS的ConditionObject,是AQS的内部类,实现等待通知机制. 1.条件队列 条件队列与AQS中的同步队列有所不同,结构图如下: 两者区别: 1.链表 ...

随机推荐

  1. loj2058 「TJOI / HEOI2016」求和 NTT

    loj2058 「TJOI / HEOI2016」求和 NTT 链接 loj 思路 \[S(i,j)=\frac{1}{j!}\sum\limits_{k=0}^{j}(-1)^{k}C_{j}^{k ...

  2. orm-1

    - ORM什么是? 类名 ---> 数据库表 对象 ---> 记录 对象.属性 ---> 字段 - ORM的优缺点: 优点: 可跨平台,可以通过对象.属性取值,对象.方法,让该方法内 ...

  3. nginx架构分析之 架构

    Nginx服务器使用 master/worker 多进程模式. 主进程(Master process)启动后,会接收和处理外部信号: 主进程启动后通过fork() 函数产生一个或多个子进程(work ...

  4. LCA的几种做法

    P3379 LCA $ 1:$蜗牛爬式 void dfs(int u,int fa) { f[u]=fa;//预处理father for(int i=head[u]; i; i=e[i].nxt) i ...

  5. SSM 实现支付宝支付功能(图文详解+完整代码)

    阅读本文大概需要 4 分钟. 前言 本教程详细介绍了如何使用ssm框架实现支付宝支付功能.本文章分为两大部分,分别是「支付宝测试环境代码测试」和「将支付宝支付整合到ssm框架」,详细的代码和图文解释, ...

  6. VS 点击页面自动定位到解决方案资源管理器目录位置

    点击工具→选项→项目和解决方案:勾上“在解决方案资源管理器中跟踪活动项”.

  7. Ubuntu16.04.1上搭建分布式的Redis集群,并使用C#操作

    为什么要集群: 通常为了,提高网站的响应速度,总是把一些经常用到的数据放到内存中,而不是放到数据库中,Redis是一个很好的Cache工具,当然了还有Memcached,这里只讲Redis.在我们的电 ...

  8. Mysql之Incorrect string value: '\xF0\x9F\x98\x89 \xE6... 保存emoji表情

    错误信息如下: Incorrect string value: '\xF0\x9F\x98\x89 \xE6...' 问题产生的原因是字符串不兼容4字节的unicode导致的,一般我们常见的表情编码等 ...

  9. 前端知识点回顾之重点篇——CSS中flex布局

    flex布局 来源: http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html?utm_source=tuicool 采用 Flex 布局的元素 ...

  10. WebGL学习笔记(六):纹理贴图

    只可以绘制纯色的模型是不够的,为了呈现出更真实的模型,我们还需要通过纹理贴图给模型进行上色. 丢失上下文 GPU作为一种公用资源,是会被多个进程同时使用的,在资源不足的情况下(比如PC或手机系统进入休 ...