libevent源码分析之Reactor模式

一、概述

libevent使用了Reactor模式,实现了高效的事件驱动机制。

二、Reactor定义

1、Reactor是一种事件驱动机制。应用程序不是主动的调用某个系统API完成处理,Reactor逆置了事件处理流程,应用程序注册回调函数到Reactor上,如果相应的事件(比如读、写、错误)发生,Reactor将回调应用程序注册的接口。
2、Reactor结构五个关键的参与者:

  • 描述符(handle):由操作系统提供,用来识别每一个事件,如socket描述符、文件描述符等。
  • 同步事件分离器(demultiplexer):一个函数,用于等待事件的发生。它会被阻塞,直到分离器分离的描述符集合上有事件发生。比如select、epoll_wait等。
  • 事件处理接口(event handle):描述了对应事件(读取,写出、超时)的某种操作(回调)。
  • 具体的事件处理器:是事件处理器接口的实现。
  • Reactor管理器:事件处理器,定义了一些接口,用于应用程序控制事件调度,提供注册、删除事件处理器和相关的描述符接口。

3、Reactor优点
Reactor使用同步事件分离器来等待描述符的事件发生。一旦事件发生,Reactor管理器调用事件处理接口,最终执行具体的事件处理器函数。

具有如下的优点:

  • 响应快,不必为单个同步操作所阻塞;
  • 编程简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;
  • 可扩展性,可以方便的通过增加Reactor实例的数量来解决单实例负载过高问题;
  • 可复用性,Reactor框架本身与具体事件处理逻辑无关,具有很高的复用性;

三、Reactor架构

1、下图是Reactor的架构图

在这里插入图片描述

2、libevent对应的框架图

在这里插入图片描述

3、libevent的Reactor具体实现

在这里插入图片描述

四、libevent的reactor实现

1、主要数据结构:

  • event:一个结构体,主要包含了一个socket文件句柄,以及需要监听的事件,以及事件触发后要执行的回调。
  • event_base:添加、移除事件,检测事件是否激活并执行事件回调或超时。
  • event_map_io:fd为key,evmap_io为value的hashtable。

2、event结构

event存放socket句柄以及句柄上监听的事件、超时时间,事件触发时执行的回调函数、参数以及优先级等。另外还存储activequeues、eventqueue、common_timeout_list链表里下一个event的指针。
数据结构说明如下:

#define EV_TIMEOUT 0x01 //是否设置超时
#define EV_READ 0x02 //是否监听读事件
#define EV_WRITE 0x04 //是否监听写事件
#define EV_SIGNAL 0x08 //是否监听信号
#define EV_PERSIST 0x10 //是否可以重复触发(如果没设置这个标记,那么触发一次后,事件监听会被移除)
#define EV_ET 0x20 //是否使用边沿触发

struct event {
    
    
    evutil_socket_t ev_fd; //socket句柄
	struct event_base *ev_base; //指向event_base
	
	short ev_events;  //监听的事件,TIMEOUT、READ、WRITE、SIGNAL、PERSIST、ET
	short ev_res;	//触发的事件,TIMEOUT、READ、WRITE、SIGNAL
	short ev_flags; //EVLIST_TIMEOUT、EVLIST_INSERTED、EVLIST_SIGNAL、EVLIST_ACTIVE、EVLIST_INTERNAL、EVLIST_INIT
	ev_uint8_t ev_pri;	//事件监听触发后,控制待执行回调的先后顺序
	ev_uint8_t ev_closure; //EV_CLOSURE_NONE,EV_CLOSURE_SIGNAL,EV_CLOSURE_PERSIST
	struct timeval ev_timeout;  //超时时间 
	void (*ev_callback)(evutil_socket_t, short, void *arg);  //事件触发后,执行的回调函数
	void *ev_arg; //ev_callback回调时附带的参数
	
	TAILQ_ENTRY(event) ev_active_next; //activequeue里,指向下一个event
	TAILQ_ENTRY(event) ev_next; //eventqueue里,指向下一个event
	union {
    
    
		TAILQ_ENTRY(event) ev_next_with_common_timeout; //common超时队列的下一个event
		int min_heap_idx; //超时最小堆里的索引
	} ev_timeout_pos;
	
	union {
    
    
		struct {
    
    
			TAILQ_ENTRY(event) ev_io_next; //evmap_io的events里,指向下一个event
			struct timeval ev_timeout; //如果是持久事件,会把超时时间存在这里,下次添加的时候,继续用这个超时时间
		} ev_io; //io事件数据结构
		
		struct {
    
    
			TAILQ_ENTRY(event) ev_signal_next; //evmap_signal的events里,指向下一个event
			short ev_ncalls; //接收到的信号数量
			short *ev_pncalls; //当前剩余的信号数量指针
		} ev_signal; //used for signal events
	} _ev;
};

3、event_base结构

//event_base_config的flag标记,这些flags可以改变event_base的行为
enum event_base_config_flag {
    
    
	EVENT_BASE_FLAG_NOLOCK = 0x01, //是否加锁,多线程时需要加锁
	EVENT_BASE_FLAG_IGNORE_ENV = 0x02, //是否忽略EVENT_XXX环境变量
	EVENT_BASE_FLAG_STARTUP_IOCP = 0x04, //使用IOCP(false的话,windows下使用select),windows可用
	EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08, //是否用不缓存的时间
	EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10 //使用libevent的内部change-list来批量添加或删除,可以减少系统调用的次数。通过设置EVENT_EPOLL_USE_CHANGELIST来激活这个配置
};

//获取当前操作系统上,event_base支持的特性
enum event_method_feature {
    
    
    EV_FEATURE_ET = 0x01, //边缘触发,
    EV_FEATURE_O1 = 0x02, //事件的触发消耗是O(1),还是O(n)
    EV_FEATURE_FDS = 0x04 //文件描述符
};
struct event_base {
    
    
	enum event_base_config_flag flags; //event_base初始化的时候设置,NOLOCK、IGNORE_ENV、STARTUP_IOCP、NO_CACHE_TIME、EPOLL_USE_CHANGELIST
	
	const struct eventop *evsel; //某种模式下操作(select、epoll等)的函数指针表 
	void *evbase; //某种模式(select、epoll等)的特定数据结构

	const struct eventop *evsigsel; //signal操作的函数指针表
	struct evsig_info sig; //signal操作的数据结构
	
	struct event_changelist changelist; //缓存监听事件的变化,在分发函数调用之前,才调用epoll_ctl修改监听的事件,在多次修改同一个fd监听的情况下可以避免不必要的系统调用。
	
	int virtual_event_count; //虚拟event数量
	int event_count; //事件数量
	int event_count_active; //active事件数量

	int event_gotterm; //执行完当前的loop,然后中断循环
	int event_break; //立即中断当前的loop,并中断循环
	int event_continue; //中断执行evmap里剩余event的callback

	int event_running_priority; //事件优先级
	int running_loop; //标记当前正在执行event_base_loop
	
	struct timeval event_tv; //每次loop会记录当前的时间,用来检测时间是否有回退
	struct timeval tv_cache; //每次loop会缓存一个时间

	struct event_list eventqueue; //事件队列
	struct event_list *activequeues; //active队列
	int nactivequeues; //activequeues队列数量

	struct deferred_cb_queue defer_queue; //延迟回调队列

	struct event_io_map io; //io_map
	struct event_signal_map sigmap; //signal_map
	
	struct min_heap timeheap; //超时时间最小堆
	struct common_timeout_list **common_timeout_queues; //通用超时队列
	int n_common_timeouts; //通用超时队列的数量
	int n_common_timeouts_allocated; //分配的通用超时队列数量
	
	

	
	struct timeval tv_clock_diff; //tv时间和clock时间的偏差
	time_t last_updated_clock_diff; //clock时间的秒数
};

4、event_base主要数据结构关系图

在这里插入图片描述

5、evmap_io数据结构

evmap_io维护了一个fd上监听的event列表,每个event里主要包含了监听的事件类型、超时时间以及回调函数。

struct evmap_io {
    
    
	struct event_list events; //event链表
	ev_uint16_t nread; //events里包含的read监听事件数量
	ev_uint16_t nwrite; //events里包含的write监听事件数量
};

五、event主要接口

函数原型 功能
struct event *event_new(struct event_base *, evutil_socket_t, short, event_callback_fn, void *) 创建一个新的事件结构体。fd和events参数决定了触发事件的条件。条件触发会用fd,触发的事件( EV_READ、EV_WRITE或EV_SIGNAL、EV_TIMEOUT、EV_ET)、callback_arg指针回调callback
void event_free(struct event *) 释放一个event
int event_base_once(struct event_base *, evutil_socket_t, short, event_callback_fn, void *, const struct timeval *) 执行一次event
int event_add(struct event *ev, const struct timeval *timeout) 添加一个event到eventqueue。如果event的参数已经有超时,调用event_add()会替换老的超时时间,如果tim eout为空,则会清掉超时
int event_del(struct event *) 从events监控列表中移除一个事件
void event_active(struct event *ev, int res, short ncalls) 激活event。当调用event_base_dispatch()或event_base_loop(),事件回调会被执行
int event_pending(const struct event *ev, short events, struct timeval *tv) 判定事件events是否被event监听了,返回events中被监听的事件
int event_initialized(const struct event *ev) 判断event是否已经初始化了
struct event_base *event_get_base(const struct event *ev) 获取event所属的event_base
evutil_socket_t event_get_fd(const struct event *ev) 获取event的fd
short event_get_events(const struct event *ev) 获取event监听的events
event_callback_fn event_get_callback(const struct event *ev) 获取event的callback函数
void *event_get_callback_arg(const struct event *ev) 获取event的callback回调时带的参数
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); 初始化event的属性
size_t event_get_struct_event_size(void) 返回event结构体的大小
int event_priority_set(struct event *, int) 设置event的优先级

六、eventbase主要接口

函数原型 功能
struct event_config *event_config_new(void) 创建一个新的event_config对象
void event_config_free(struct event_config *cfg) 释放event_config对象
struct event_base *event_base_new(void) 创建一个event_base
struct event_base *event_base_new_with_config(const struct event_config *) 用event_base_new_with_config()配置个性化参数初始化event_base
int event_reinit(struct event_base *base) 在fork后调用,用于重新初始化一些属性
void event_base_free(struct event_base *) 释放event_base分配的所有内存,这个函数不会关闭任何fd
int event_base_dispatch(struct event_base *) 调用后,只有当不再有event激活或调用了event_base_loopbreak()或event_base_loopexit()才会退出。成功返回0,失败返回-1,由于没有事件pending或active而退出返回1
int event_base_loop(struct event_base *, int) 等待event激活,执行它的回调。这个比event_base_dispatch()更灵活。默认情况下,这个循环将执行到没有pending或激活的事件或者调用event_base_loopbreak()、event_base_loopexit()。flags标识EVLOOP_ONCE或EVLOOP_NONBLOCK,可以通过传入flag来改变行为
int event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv) 获取缓存的timeofday
const struct timeval *event_base_init_common_timeout(struct event_base *base, const struct timeval *duration) 设置一个超时队列,放入这个超时队列时的事件,超时时间相同。这个可以避免用最小堆,最小堆插入和调整的复杂度是O(logN),而相同超时时间的队列保证了队列里的事件按放入队列的先后顺序超时,插入和检查超时的复杂度度都是O(1)
int event_base_loopexit(struct event_base *, const struct timeval *) 在指定的时间之后退出事件循环,在给定计时器过期后的下一个event_base_loop()会正常完成(处理所有排队事件),然后退出。循环结束后的时间,null表示在运行所有当前活动的事件后立即退出。成功返回0,错误返回-1。
int event_base_loopbreak(struct event_base *) 立即终止进行中的event_base_loop()。在下一个event事件完成后,event_base_loop()被终止循环。通常event_base_loopbreak()在event的回调里被调用。
int event_base_got_exit(struct event_base *) 在调用event_loopexit()后直到下一次event loop执行前,都会返回true。状态会在下个eventloop执行前清掉
int event_base_got_break(struct event_base *) 在event_loopbreak()被调用后直到下一次event loop执行前都返回true
int event_base_get_features(const struct event_base *base) 获取event_method_feature
int event_config_require_features(struct event_config *cfg, int feature) 设置一个feature
int event_config_set_flag(struct event_config *cfg, int flag) 设置一个flagv
int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus) 设置CPU数量,只对IOCP有效
const char *event_get_version(void) 获取libevent版本字符串
ev_uint32_t event_get_version_number(void) 获取libevent整数版本号
const char *event_base_get_method(const struct event_base *) 返回内核事件系统的标识比如kqueue、epoll等
const char **event_get_supported_methods(void) 返回所有libevent支持的event通知系统
int event_base_get_features(const struct event_base *base) 获取event_base支持的特性,按位标记
int event_config_require_features(struct event_config *cfg, int feature) 修改event_base的特性
int event_config_set_flag(struct event_config *cfg, int flag) 设置flag
int event_config_avoid_method(struct event_config *cfg, const char *method) 禁用libevent的某种event通知系统
int event_base_priority_init(struct event_base *, int) 设置优先级的数量
void event_set_log_callback(event_log_cb cb) 设置libevent日志的回调函数
void event_set_fatal_callback(event_fatal_cb cb) 设置fatal回调函数
void event_set_mem_functions(void *(*malloc_fn)(size_t sz), void *(*realloc_fn)(void *ptr, size_t sz), void (*free_fn)(void *ptr)) 重设内存分配的函数
void event_enable_debug_mode(void) 开启调试模式,这个方法需要在任何event或event_base被创建前调用

六、evmap主要接口

函数原型 功能
void evmap_io_initmap(struct event_io_map* ctx) 初始化evmap
void evmap_io_clear(struct event_io_map* ctx) 清理evmap
int evmap_io_add(struct event_base *base, evutil_socket_t fd, struct event *ev) 给某个fd上添加io事件(EV_READ、EV_WRITE)
int evmap_io_del(struct event_base *base, evutil_socket_t fd, struct event *ev) 从某个fd上移除io事件(EV_READ、EV_WRITE)
void evmap_io_active(struct event_base *base, evutil_socket_t fd, short events) 激活某个fd上等待的事件(EV_READ

信号相关的接口就不列了。

猜你喜欢

转载自blog.csdn.net/gamekit/article/details/112727897