libevent

背景

源码版本:2.1.11-stable

核心思想:Reactor模型(事件驱动)

处理的事件类型:网络IO读写,定时器,信号

reactor模型

它是一种“事件驱动”机制。程序想处理某个事件,需要提供相应的接口并注册到reactor上;如果相应的事件发生,reactor将主动调用此事件注册的接口,这些接口也称为“回调函数”。

使用libevent也是向libevent框架注册相应的事件和回调函数;当这些被注册的事件发生时,libevent会调用这些回调函数处理相应的事件。

 

reactor模型的组件:

  • 事件源
  • reactor框架
  • 事件多路复用机制
  • 事件处理程序

事件源:

事件源用一个整型变量表示,libevent支持的事件源分两类:一类是大于0的文件描述符,用于socket通信;另一类是小于0,有定时器、信号和用户自定义事件。

  • 通信套接字,通常注册它的IO读写事件

事件多路复用机制(event demultiplexer):

  select 、poll、epoll等,;

  程序首先将其注册了关心事件的回调的套接字注册到event demultiplexer上,

  当有事件到达时,event demultiplexer会向已经注册的套接字集合发出通知 “一个或多个事件已经就绪”;

  对应到libevent, 使用了结构体eventop对select、poll等进行了封装,以统一接口来实现IO多路复用机制;

reactor:

  事件管理的接口,内部通过event demultiplexer进行事件的注册和注销操作;并运行事件循环,当有事件进入“就绪”状态时,就调用注册事件的回调函数来处理事件;

  对应到libevent,就是结构体event_base;

事件处理程序:

  事件处理程序提供一级接口,每个接口对应一种类型的事件,供reactor在相应事件发生时调用;

  对应到libevent,就是结构体event;

库的全局设置

  • 日志消息
  • 处理致使错误
  • 内存管理
  • 锁和线程
  • 调试锁的使用
  • 调试事件的使用
  • 检测库的版本
#define EVENT_LOG_DEBUG 0
#define EVENT_LOG_MSG   1
#define EVENT_LOG_WARN  2
#define EVENT_LOG_ERR   3
typedef void (*event_log_cb)(int severity, const char *msg);
void event_set_log_callback(event_log_cb cb);

  手写日志回调,将其作为参数并调用event_set_log_callback(),将覆盖日志的默认行为;

  日志默认输出到stderr, 再次调用event_set_log_callback()并传参NULL将恢复默认行为;

 

typedef void (*event_fatal_cb)(int err);
void
event_set_fatal_callback(event_fatal_cb cb);

  程序执行期间,遇到致使错误的默认行为是退出程序;

  设置退出回调,可在程序异常退出前执行回调;

 

void event_set_mem_functions(
    void *(*malloc_fn)(size_t sz),
    void *(*realloc_fn)(void *ptr, size_t sz),
    void (*free_fn)(void *ptr));

  替换默认的内存管理函数malloc, realloc, free

 

const char *event_get_version(void);
ev_uint32_t event_get_version_number(void);

  获取libevent版本信息

 

具体信息,参考《从一万英尺下看libevent》

event_base相关源码解析

struct event_base
  • 作用:保存一个libevent调度回路的信息和状态(监视所有就绪事件和未决事件,并通知就绪事件)
  • 特点:是一个不透明结构体
  • 分配方法:event_base_new() | event_base_new_with_config()

 

struct event_base *event_base_new(void);
  • 功能:分配一个默认的event_base结构体
  • 返回:成功返回一个具有默认设置的指针,失败返回NULL

 

struct event_base *event_base_new_with_config(const struct event_config *);
  • 创建一个带有配置属性的event_base,需要传入event_config结构体
  • 成功返回带配置属性的指针,失败返回NULL

 

struct event_config *event_config_new(void);
  • 功能:先创建event_config结构体,它可以保存event_base属性
  • 返回:成功返回可用结构体指针,失败返回NULL

 

int event_config_avoid_method(struct event_config *cfg, const char *method);
  • 功能:禁用某种方法

 

int event_config_require_features(struct event_config *cfg, int feature);
enum event_method_feature { //flag
  EV_FEATURE_ET = 0x01,        //边沿触发
  EV_FEATURE_O1 = 0x02, //添加、删除单个事件,或者确定哪个事件是激活状态的操作的时间复杂度是O(1)
  EV_FEATURE_FDS = 0x04, //允许文件描术符和套接字
  EV_FEATURE_EARLY_CLOSE = 0x08//在不需要检测所有未激活连接的情况,检测某个连接是否关闭
}
  • 功能:声明某种特性
  • 返回:成功返回0,失败返回-1

 

int event_config_set_flag(struct event_config *cfg, int flag);
enum event_base_config_flag {
  EVENT_BASE_FLAG_NOLOCK = 0x01, //不分配锁
  EVENT_BASE_FLAG_IGNORE_ENV = 0x02, //不检测EVENT_* 环境变量
  EVENT_BASE_FLAG_STARTUP_IOCP = 0x04, //仅windows可用
  EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08, //超时回调执行后检测当前时间
  EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,//使用epoll_changelist特征
  EVENT_BASE_FLAG_PRECISE_TIMER = 0x20 //使用效率低但更精准的计时器
}
  •  功能:设置event_base的工作特性
  • 返回:成功返回0,失败返回-1

 

const char **event_get_supported_methods(void);
  • 功能:返回所有支持的事件通知机制

 

const char *event_base_get_method(const struct event_base *);
  • 功能:返回正在使用的机制(方法)

 

int event_base_get_features(const struct event_base *base);
  • 功能:检查并返回一个event_base已设置的特征属性

 

void event_base_free(struct event_base *);
  • 功能:从内存删除一个event_base

 

int    event_base_priority_init(struct event_base *, int);
  • 功能:设置最大优先级数目

 

int event_reinit(struct event_base *base);
  • fork后重新初始化event_base

 

事件循环相关源码解析

事件循环过程中,libevent是在等待并通知已经注册并发生的事件。

 

int event_base_loop(struct event_base *base, int flags)
flags:
  #define EVLOOP_ONCE 0x01
  #define EVLOOP_NONBLOCK 0x02
  #define EVLOOP_NO_EXIT_ON_EMPTY 0x04
  • 功能:循环检查是否有注册事件被激活,并执行激活事件

 

int event_base_dispatch(struct event_base *event_base)
  • 功能:一直监视未决和就绪事件,直到所有事件都没有了或者调用了 event_base_loopbreak() 或event_base_loopexit()
  • 返回:成功返回0,失败返回-1,如果没有监视的事件了返回1

 

int event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv);
  • 功能:在事件回调函数内部,获取event_base缓存的当前时间的近似值
  • 返回:成功返回0

 

void event_base_dump_events(struct event_base *, FILE *);
  • 功能:导出event_base当前监视的事件列表到本地文件(用于程序调试)

 

事件

事件是libevent的基本操作单元,每个事件代表一组条件的集合,条件包括:

  • 文件描述符已经就绪,可读写;
  • 文件描述符变为就绪(边沿触发),可读写;
  • 超时事件;
  • 发生信号;
  • 用户触发事件;

 

调用libevent函数设置事件并关联到event_base之后,该事件进入“已初始化"状态(initiailzed);

此时,可以将其添加到event_base中,这使得其进入“未决”状态(pending);

在未决状态下,如果触发事件的条件发生(如超时,文件描述符状态改变),则事件进入“激活”状态(active),用户注册的事件回调函数将被执行;

如果事件配置为“持久的”(persistent),事件将保持为未决状态,否则事件不再未决;

删除操作可心让未决事件成为非未决(已初始化)的;

添加操作可以让非未决事件再次成为为未决的;

创建事件

#define EV_TIMEOUT   0x01 //超时,在将事件添加到event_base时使用
#define EV_READ      0x02 //文件描述符可读
#define EV_WRITE     0x04 //文件描述符可写
#define EV_SIGNAL    0x08 //信号发生
#define EV_PERSIST   0x10 //未决状态持久
#define EV_ET        0x20 //边沿触发
#define EV_FINALIZE  0x40 //非阻塞调用event_del()
#define EV_CLOSED    0x80 //连接关闭
typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg);
  • 功能:创建一个新事件。fd为非负时监视其读写,events是监视的事件类型的位集合
  • 返回:成功返回新事件指针,失败返回NULL
  • 说明:所有新创建的事件都处于已初始化和非未决状态

事件的持久性

默认情况下,事件从未决状态变成就绪状态后,事件将在执行事件回调前成为非未决状态;

如果想让事件再次成为未决状态,可以在回调函数内部再次将其添加到event_base;

然而,如果事件创建时设置了EV_PERSIST标志,则事件变成就绪态执行回调前不会变成非未决状态;

如果想让未决状态事件变成非未决状态,可调用event_del()执行删除操作;

创建只关心超时的事件

#define evtimer_new(b, cb, arg)        event_new((b), -1, 0, (cb), (arg))
#define evtimer_add(ev, tv)            event_add((ev), (tv))
#define evtimer_del(ev)                event_del(ev)
#define evtimer_pending(ev, tv)        event_pending((ev), EV_TIMEOUT, (tv))
#define evtimer_initialized(ev)        event_initialized(ev)

使用这些宏函数,可以使设置纯超时事件更简便,当然,你也可以直接使用原生操作函数

 

创建信号事件

#define evsignal_add(ev, tv)        event_add((ev), (tv))
#define evsignal_del(ev)            event_del(ev)
#define evsignal_pending(ev, tv)    event_pending((ev), EV_SIGNAL, (tv))
#define evsignal_initialized(ev)    event_initialized(ev)

 

让事件变成未决状态和非未决状态

int event_add(struct event *ev, const struct timeval *timeout);
int event_del(struct event *ev)

 设置事件的优先级

int event_priority_set(struct event *ev, int pri);

示例:

 

获取事件状态

int event_pending(const struct event *ev, short event, struct timeval *tv);

  功能:判断给定事件是否是未决或就绪状态

 

evutil_socket_t event_get_fd(const struct event *ev);

  功能:返回事件的文件描述符

 

#define event_get_signal(ev) ((int)event_get_fd(ev))

  功能:返回事件的信号值

 

struct event_base *event_get_base(const struct event *ev);

  功能:返回事件的event_base

 

short event_get_events(const struct event *ev);

  功能:返回事件的标志

 

event_callback_fn event_get_callback(const struct event *ev);

  功能:返回事件的回调函数

 

void *event_get_callback_arg(const struct event *ev);

  功能:返回事件回调函数的参数

 

void event_get_assignment(const struct event *event,
    struct event_base **base_out, evutil_socket_t *fd_out, short *events_out,
    event_callback_fn *callback_out, void **arg_out);

  功能:返回上述所有

 

创建一次触发事件

int event_base_once(struct event_base *, evutil_socket_t, short, event_callback_fn, void *, const struct timeval *);

 

 手动激活事件

void event_active(struct event *ev, int res, short ncalls);

 

参考

来自官方文档《从一万英尺外看libevent》

posted on 2019-12-31 21:21  sermatec江  阅读(475)  评论(0编辑  收藏  举报