libevent源码分析

原创 2007年09月30日 15:07:00

  libevent实现了网络IO,timer,signal的事件触发机制. 可以很方便的应用于event-driven服务器中,作为其底层事件处理模块. 比较成功的案例有 memcache(分布式缓存), PLB(负载均衡器)等.

  最近研究了一下libevent的源码, 版本是1.3b,可以大概分成几个模块:

♦ 事件处理框架

♦ 事件引擎模块

♦ Buffer管理模块

♦ 信号处理模块

 1. 事件处理框架

1.1 event_init() 初始化

  首先要隆重介绍event_base对象:

struct event_base {
    const struct eventop *evsel;
    void *evbase;
    int event_count;        /* counts number of total events */
    int event_count_active; /* counts number of active events */
   
    int event_gotterm;      /* Set to terminate loop */
       
    /* active event management */
    struct event_list **activequeues;
    int nactivequeues;

    struct event_list eventqueue;
    struct timeval event_tv;

    RB_HEAD(event_tree, event) timetree;
};

   event_base对象整合了事件处理的一些全局变量,  角色是event对象的"总管家", 他包括了事件引擎函数对象(evsel, evbase), 当前入列事件列表(event_count, event_count_active, eventqueue), 全局终止信号(event_gotterm), 活跃事件列表(avtivequeues), 事件队列树(timetree)...

   初始化时创建event_base对象, 选择 当前OS支持的事件引擎(epoll, poll, select...)并初始化, 创建全局信号队列(signalqueue), 活跃队列的内存分配( 根据设置的priority个数,默认为1).

 1.2 event_set() 事件定义

    event_set来设置event对象,包括所有者event_base对象, fd, 事件(EV_READ| EV_WRITE), 回掉函数和参数,事件优先级是当前event_base的中间级别(current_base->nactivequeues/2). event对象的定义见下:

struct event {
    TAILQ_ENTRY (event) ev_next;
    TAILQ_ENTRY (event) ev_active_next;
    TAILQ_ENTRY (event) ev_signal_next;
    RB_ENTRY (event) ev_timeout_node;

    struct event_base *ev_base;
    int ev_fd;
    short ev_events;
    short ev_ncalls;
    short *ev_pncalls;  /* Allows deletes in callback */

    struct timeval ev_timeout;

    int ev_pri;     /* smaller numbers are higher priority */

    void (*ev_callback)(int, short, void *arg);
    void *ev_arg;

    int ev_res;     /* result passed to event callback */
    int ev_flags;
};

1.3 event_add() 事件添加:

   int event_add(struct event *ev, struct timeval *tv)

   这个接口有两个参数, 第一个是要添加的事件, 第二个参数作为事件的超时值(timer). 如果该值非NULL, 在添加本事件的同时添加超时事件(EV_TIMEOUT)到时间队列树(timetree), 根据事件类型处理如下:  

   EV_READ  =>  EVLIST_INSERTED  => eventqueue

   EV_WRITE  =>  EVLIST_INSERTED  => eventqueue

   EV_TIMEOUT => EVLIST_TIMEOUT => timetree

  EV_SIGNAL  => EVLIST_SIGNAL => signalqueue

1.4 event_base_loop() 事件处理主循环

   这里是事件的主循环,只要flags不是设置为EVLOOP_NONBLOCK, 该函数就会一直循环监听事件/处理事件.

   每次循环过程中, 都会处理当前触发(活跃)事件:

   (a). 检测当前是否有信号处理(gotterm, gotsig), 这些都是全局参数,不适合多线程

   (b). 时间更新,找到离当前最近的时间事件, 得到相对超时事件tv

   (c). 调用事件引擎的dispatch wait事件触发, 超时值为tv, 触发事件添加到activequeues

   (d). 处理活跃事件, 调用caller的callbacks (event_process_acitve)

2. 事件引擎模块 :

   Linux下有多种I/O复用机制, .来处理多路事件监听, 常见的有epoll, poll, select, 按照优先级排下来为:

  • evport
  • kqueue
  • epoll
  • devpoll
  • rtsig
  • poll
  • select

   在event_init()选择事件引擎时,按照优先级从上向下检测, 如果检测成功,当前引擎被选中.每个引擎需要定义几个处理函数,以epoll为例:

struct eventop epollops = {
    "epoll",
    epoll_init,
    epoll_add,
    epoll_del,
    epoll_recalc,
    epoll_dispatch,
    epoll_dealloc
};

3. Buffer管理模块:

   libevent定义了自己的buffer管理机制evbuffer, 支持多种类型数据的read/write功能, 包括不定长字符串,buffer中内存采用预分配/按需分配结合的方式, 可以比较方便的管理多个数据结构映射到内存buffer.

   需要拉出来介绍的是evbuffer_expand()函数, 当内部内存不够时,需要expand, 这里采用预分配的方式,如果需要长度<256字节,预分配256字节, 同时内存成倍增长,一直到大于需要的长度.

4.  信号处理模块

   信号处理单独提出来,主要是libevent的信号处理比较轻巧, 从而很好融合到event机制.

   singal模块初始化(evsignal_init)时, 创建了UNIX域socket ( pipe)作为内部消息传递桥梁:

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, ev_signal_pair) == -1)
        event_err(1, "%s: socketpair", __func__);

    FD_CLOSEONEXEC(ev_signal_pair[0]);
    FD_CLOSEONEXEC(ev_signal_pair[1]);

    fcntl(ev_signal_pair[0], F_SETFL, O_NONBLOCK);

    event_set(&ev_signal, ev_signal_pair[1], EV_READ,
        evsignal_cb, &ev_signal);
    ev_signal.ev_flags |= EVLIST_INTERNAL;

   evsignal_add(), 添加信号事件, 关联信号处理方法(sigaction)

   实际运行过程中,如果某singal发生, 对应的信号处理方法被调用, write a character to pipe

   同时pipe的另一端被激活, 添加信号到singalqueue, 在事件循环中evsignal_process处理信号callbacks

5. 其他资料:

libevent官方网址:   http://www.monkey.org/~provos/libevent/ 

比较好的文档:

http://unx.ca/log/category/libevent/

Libevent源码分析(一):最小堆

Libevent中的timeout事件是使用最小堆来管理维护的.代码位于. 看函数命名和代码风格应该是一个C++程序员,函数名都挺好懂的,只是下面这个结构体变量命名比较坑.... type...
  • u013366022
  • u013366022
  • 2016年11月30日 15:03
  • 282

libevent源码分析-event

1、event结构2、event相关接口3、Libevent对event的管理
  • KangRoger
  • KangRoger
  • 2015年08月17日 22:50
  • 1552

libevent源码分析:epoll

epoll是linux下的最高效io后端,它的操作接口是epollopsconst struct eventop epollops = { "epoll", epoll_init, ...
  • xtchina
  • xtchina
  • 2016年07月10日 17:53
  • 985

Libevent源码分析

推荐博客:Libevent源码分析
  • woniuye
  • woniuye
  • 2017年12月22日 17:26
  • 16

libevent源码分析

1、入门 1.1、概述 Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的网络库。Libevent有几个显著的亮点:  (1)事件驱动(event-dri...
  • prochsh
  • prochsh
  • 2013年10月15日 18:05
  • 588

Libevent源码分析-----开篇

相信来看本系列的文章的读者,都不会是刚刚接触Libevent的用户。这里就不说Libevent的优点和怎么安装使用Libevent了。我是想介绍其他东西。...
  • luotuo44
  • luotuo44
  • 2014年07月30日 15:08
  • 7642

Libevent源码分析-----与event相关的一些函数和操作

Libevent提供了一些与event相关的操作函数。本文就重点讲一下这方面的源代码。   在Libevent中,无论是event还是event_base,都是使用指针而不会使用变量。实际上,如果...
  • luotuo44
  • luotuo44
  • 2014年08月21日 22:49
  • 3416

[libevent源码分析] event_set

libevent源码分析
  • youkuxiaobin
  • youkuxiaobin
  • 2015年03月07日 05:55
  • 1512

Libevent源码分析-event_base

event_base数据结构 初始化event_base 相关接口
  • KangRoger
  • KangRoger
  • 2015年08月20日 10:46
  • 2096

[libevent源码分析] event_set

libevent使用event来封装网络事件回调,参数、fd。。。等一些信息,函数很简单 [cpp] view plain copy print? void  ev...
  • wzsy
  • wzsy
  • 2016年10月10日 10:48
  • 143
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:libevent源码分析
举报原因:
原因补充:

(最多只允许输入30个字)