栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

libevent是怎么选择底层实现的

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

libevent是怎么选择底层实现的

1. libevent到底使用哪种io模式来作为底层实现

libevent实际封装了很多IO复用模式,比如evport,select,poll,epoll,devpoll等等,这些都是不同操作系统下的I/O多路复用模式,那么我们怎么知道当前使用的是哪种模式呢?

说到底层实现,那就不得不说说event-config.h文件的生成。

1.1 event-config.h文件的生成

在上一篇《libevent目录结构分析》中,我们提到event-config.h,它存放了很多宏定义配置。

event-config.h这个文件并不是一直不变的,这里有一个过程:

  • 首先,configure在检查环境依赖的时候会生成config.h和Makefile;
  • 然后,Makefile会根据config.h生成event-config.h;

event-config.h基本是存放宏定义的,如下:


#define EVENT__HAVE_DLFCN_H 1

#define EVENT__HAVE_EPOLL 1



#define EVENT__HAVE_EPOLL_CTL 1

#define EVENT__HAVE_ERRNO_H 1

这个是在我的redhat环境下编译以后生成的部分宏定义,EVENT__HAVE_EPOLL这个宏定义为1则说明我的redhat环境是支持epoll的,但这并不能说明我当前就是使用的epoll,因为redhat同样支持select和poll。

1.2 I/O模式选择

那么底层实现到底用哪个呢,看下面代码:

struct event_config *config;
struct event_base *base;

config = event_config_new();
 
event_config_avoid_method(config, "select");
 
event_config_require_features(config, EV_FEATURE_FDS);
base = event_base_new_with_config(config);
if (!base) { 
 exit(1); }
event_config_free(config);

这是源码包里面whatsnew-2.0.txt里面的例子,event_config_require_features这个函数其实就指定了底层实现,那么具体过程是怎样的呢。

  • 首先,event_config_new生成了一个event_config,struct event_config定义如下:
struct event_config {
	TAILQ_HEAD(event_configq, event_config_entry) entries;

	int n_cpus_hint;
	struct timeval max_dispatch_interval;
	int max_dispatch_callbacks;
	int limit_callbacks_after_prio;
	enum event_method_feature require_features;
	enum event_base_config_flag flags;
};

里面的枚举require_features就是决定最终用哪个,而event_config_require_features指定了require_features的值。

  • 然后在event_base_new_with_config函数中,有如下代码:
	for (i = 0; eventops[i] && !base->evbase; i++) {
		if (cfg != NULL) {
			
			if (event_config_is_avoided_method(cfg,
				eventops[i]->name))
				continue;
			
			if ((eventops[i]->features & cfg->require_features)
			    != cfg->require_features)
				continue;
		}

		
		if (should_check_environment &&
		    event_is_method_disabled(eventops[i]->name))
			continue;

		base->evsel = eventops[i];

		base->evbase = base->evsel->init(base);
	}

这段代码中,cfg就是上面的config,EV_FEATURE_FDS是0x04, 而eventops定义如下:


static const struct eventop *eventops[] = {
#ifdef EVENT__HAVE_EVENT_PORTS
	&evportops,
#endif
#ifdef EVENT__HAVE_WORKING_KQUEUE
	&kqops,
#endif
#ifdef EVENT__HAVE_EPOLL
	&epollops,
#endif
#ifdef EVENT__HAVE_DEVPOLL
	&devpollops,
#endif
#ifdef EVENT__HAVE_POLL
	&pollops,
#endif
#ifdef EVENT__HAVE_SELECT
	&selectops,
#endif
#ifdef _WIN32
	&win32ops,
#endif
	NULL
};

eventops是一个结构体指针数组,它里面具体有哪些选项就是根据event-config.h里面宏定义来的,里面元素evportops等这些都是定义在各个I/O模式的封装文件里,例如epollops就是在epoll.c里面的, selectops则是在select.c中定义的。

查看eventops各个元素里面features字段的值,发现devpollops,pollops,selectops这三种与0x04是能对上的,而devpoll并不是redhat的IO,那么在redhat环境中符合条件的就是poll和select,而event_config_avoid_method(config, “select”)这个函数调用指定不使用select,所以最终使用的就是poll。

那如果没有显示指定底层实现呢,比如这样的:

struct event_base *base = event_base_new();

还是里面的这段代码:

for (i = 0; eventops[i] && !base->evbase; i++) {
		if (cfg != NULL) {
			
			if (event_config_is_avoided_method(cfg,
				eventops[i]->name))
				continue;
			
			if ((eventops[i]->features & cfg->require_features)
			    != cfg->require_features)
				continue;
		}

		
		if (should_check_environment &&
		    event_is_method_disabled(eventops[i]->name))
			continue;

		base->evsel = eventops[i];

		base->evbase = base->evsel->init(base);
	}

符合条件的是epoll,poll,select,根据for循环条件!base->evbase 可知,第一个epoll赋给base->evbase后,循环就会结束,所以默认就是epoll。

cpp加油站(ID:xy13640954449), 作者linux服务器开发老司机,欢迎来撩!

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号