libevent源码学习(6):事件处理基础——event_base的创建

目录

前言

创建默认的event_base

event_base的配置

event_config结构体

创建自定义event_base——event_base_new_with_config

禁用(避免使用)某一种IO复用模型

设置IO复用模型需要满足的特征

设置event_base的flag特性

获取event_base所满足的特征

获取当前系统所支持的IO复用模型

总结


以下源码均基于libevent-2.0.21-stable。

前言

       要实现libevent的事件处理,最关键的就是event_base,event_base就像是一棵树,而需要进行处理的事件event就像是树上的果子,因此,在分析libevent的事件处理之前,先来分析一下event_base。

       由于event_base结构体中包含了三十多个成员,直接去分析每个成员是比较麻烦并且没有太大意义的,因此个人觉得从event_base的使用中去了解event_base各个结构体成员的作用会比较好,因此这里先来看看event_base的创建。

创建默认的event_base

       在event.c中,可以看到event_base有两种创建方式。

       目前最常用的一种方式是使用event_base_new,该函数的定义如下:

struct event_base *
event_base_new(void)
{
	struct event_base *base = NULL;
	struct event_config *cfg = event_config_new();  
	if (cfg) {  //cfg非空,说明event_config分配成功
		base = event_base_new_with_config(cfg);  //将cfg配置到base中去
		event_config_free(cfg);  //清空cfg链表
	}
	return base;
}//event.c

        可以发现,该函数是创建了一个event_base并最终返回了它,并且该函数无需传入任何参数,也就是说,如果调用该函数来创建一个event_base,那么返回得到的就是一个默认的base,而event_base_new也就是默认的event_base创建函数。关于其中使用到的event_config相关的函数,下面会分析。

       除了这种创建方式外,还有另一种创建方式event_init,该函数声明如下:

/**
  Initialize the event API.

  The event API needs to be initialized with event_init() before it can be
  used.  Sets the global current base that gets used for events that have no
  base associated with them.

  @deprecated This function is deprecated because it replaces the "current"
    event_base, and is totally unsafe for multithreaded use.  The replacement
    is event_base_new().

  @see event_base_set(), event_base_new()
 */
struct event_base *event_init(void);//event.h

       首先关注到该函数定义的描述文字中有一个@deprecated,这说明该函数是不推荐使用并且有替代品的。并提到该函数不是线程安全的,替代函数就是event_base_new。来看看该函数定义:

struct event_base *
event_init(void)
{
	struct event_base *base = event_base_new_with_config(NULL); //默认方式创建一个base 相当于调用了一个event_base_new

	if (base == NULL) {
		event_errx(1, "%s: Unable to construct event_base", __func__);
		return NULL;
	}

	current_base = base;

	return (base);
}

       在event_init函数中,创建一个新的event_base是用NULL为参数调用event_base_new_with_config的,这实际上就相当于调用了默认的event_base_new。并且在最后用current_base来保存新创建的event_base,这里的current_base是一个全局变量,这也是导致该函数线程不安全的原因。查看了一下其他资料,提到event_init实际上是老版本libevent中使用到的创建函数,不过现在相当于被废弃了,只不过为了兼容低版本,还依然保存着。

       这里分析了创建一个默认的event_base,那么如果创建一个自定义的event_base呢?并且自定义的event_base中有哪些属性是可以自定义的呢?

event_base的配置

       创建一个自定义的event_base是通过函数event_base_new_with_config来实现的,该函数声明如下:

struct event_base *event_base_new_with_config(const struct event_config *);

       该函数需要传入一个event_config参数,而该参数则包含了用户自定义的配置信息,创建得到的event_base也是根据这个参数得到的。先来看看event_config结构。

event_config结构体

       event_config结构体定义如下:

struct event_config {  //关于头结点的结构体,描述整个双向链表,event_config用于配置event_base
	TAILQ_HEAD(event_configq, event_config_entry) entries; //每个结点包含一个avoid_method 
	//定义一个头结点结构体,结构体名为event_configq,结点类型为event_config_entry,头结点变量名为entries
	int n_cpus_hint;
	enum event_method_feature require_features;  //要求满足的特征:ET、O1、FDS
	enum event_base_config_flag flags; //其他配置要求:无锁、不检查环境变量、...
};

       event_config中有4个结构体成员。其中第一个结构体成员entries是TAILQ中的头结点类型,它指向一个event_config_entry类型的结点,event_config_entry类型的定义如下:

struct event_config_entry {   //结点类型
	TAILQ_ENTRY(event_config_entry) next;
	//定义一个带前驱后驱指针的结构体变量名为next,指向的结点类型为event_config_entry
	const char *avoid_method;
};

        可以看到,event_config_entry实际上就是TAILQ中的链表结点,每一个结点都包含一个前驱和后驱结点指针,除此之外每个结点还有一个常量字符串类型的avoid_method,从变量名上来看,每个结点都定义了一个“避免使用的方法”,这个“方法”其实指的就是某种多路IO复用模型。event_config结构体的第一个成员entries作为TAILQ的头结点,连接的就是所有需要避免使用的多路IO复用模型

        event_config的第二个成员n_cpus_hint,该成员仅在启用IOCP时使用到,这里暂时不做说明;

        event_config的第三个成员require_features,是枚举类型event_method_feature,该枚举类型定义如下:

enum event_method_feature {
    /** Require an event method that allows edge-triggered events with EV_ET. */
    EV_FEATURE_ET = 0x01,
    /** Require an event method where having one event triggered among
     * many is [approximately] an O(1) operation. This excludes (for
     * example) select and poll, which are approximately O(N) for N
     * equal to the total number of possible events. */
    EV_FEATURE_O1 = 0x02,
    /** Require an event method that allows file descriptors as well as
     * sockets. */
    EV_FEATURE_FDS = 0x04
};

        event_method_feature中定义了3种特征,分别表示“是否支持边沿触发模式”、“是否支持事件的添加、删除、激活等操作的时间复杂度为O(1)”和“是否除了socket之外也支持其他的文件描述符”。因此,event_method_feature描述的应当是IO复用方法所需满足的特征。

       event_config的第四个成员flags,是枚举类型event_base_config_flag,该枚举类型定义如下:


                
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值