libevent的event_base源码分析

struct event_config {
	// 这个队列中存放的是config中需要避免的IO多路复用模型
	TAILQ_HEAD(event_configq, event_config_entry) entries;
	// CPU的个数,仅仅在win下的iocp设置了CPU个数后会智能的调整
	// event_config_set_num_cpus_hint 可以设置
	int n_cpus_hint;  
	// 检查两次新事件之间的最大时间间隔
	struct timeval max_dispatch_interval;
	// 两次检查新事件之间的执行回调函数个数的最大个数
	int max_dispatch_callbacks;
	// 如果任务的优先级小于limit_callbacks_after_prio。
	// 那么上面的两项就不会执行
	int limit_callbacks_after_prio;
	// 指定了IO多路复用使用的模型应该具有的特征
	// 通过event_config_require_features 设置
	enum event_method_feature require_features;
	enum event_base_config_flag flags;
};

// 创建一个 event_config, 调用event_config_new()
struct event_config *
event_config_new(void)
{
	struct event_config *cfg = mm_calloc(1, sizeof(*cfg));

	if (cfg == NULL)
		return (NULL);

	TAILQ_INIT(&cfg->entries);
	cfg->max_dispatch_interval.tv_sec = -1;
	cfg->max_dispatch_callbacks = INT_MAX;
	cfg->limit_callbacks_after_prio = 1;

	return (cfg);
}


struct event_base *
event_base_new(void)
{
	struct event_base *base = NULL;
	struct event_config *cfg = event_config_new();
        // 使用默认的配置
	if (cfg) {
		base = event_base_new_with_config(cfg);
		event_config_free(cfg);
	}
	return base;
}



// 使用config来生成base,但是如果无法满足config的要求那么返回NULL
// 所以需要对返回值进行判断
struct event_base *
event_base_new_with_config(const struct event_config *cfg)
{
	int i;
	struct event_base *base;
	int should_check_environment;

#ifndef EVENT__DISABLE_DEBUG_MODE
	event_debug_mode_too_late = 1;
#endif

	// 为base申请空间
	// mm_calloc 会把申请到的空间清零
	// mm_malloc 不会清零
	if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) {
		event_warn("%s: calloc", __func__);
		return NULL;
	}

	if (cfg)
		base->flags = cfg->flags;

	// 如果没有设置EVENT_BASE_FLAG_IGNORE_ENV, 忽略检查环境
	should_check_environment =
	    !(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));

	{
		struct timeval tmp;
		int precise_time =
		    cfg && (cfg->flags & EVENT_BASE_FLAG_PRECISE_TIMER);
		int flags;
		if (should_check_environment && !precise_time) {
			precise_time = evutil_getenv_("EVENT_PRECISE_TIMER") != NULL;
			if (precise_time) {
				base->flags |= EVENT_BASE_FLAG_PRECISE_TIMER;
			}
		}
		flags = precise_time ? EV_MONOT_PRECISE : 0;
		evutil_configure_monotonic_time_(&base->monotonic_timer, flags);

		gettime(base, &tmp);
	}

	min_heap_ctor_(&base->timeheap);

	base->sig.ev_signal_pair[0] = -1;
	base->sig.ev_signal_pair[1] = -1;
	base->th_notify_fd[0] = -1;
	base->th_notify_fd[1] = -1;

	TAILQ_INIT(&base->active_later_queue);

	evmap_io_initmap_(&base->io);
	evmap_signal_initmap_(&base->sigmap);
	event_changelist_init_(&base->changelist);

	base->evbase = NULL;

	if (cfg) {
		memcpy(&base->max_dispatch_time,
		    &cfg->max_dispatch_interval, sizeof(struct timeval));
		base->limit_callbacks_after_prio =
		    cfg->limit_callbacks_after_prio;
	} else {
		base->max_dispatch_time.tv_sec = -1;
		base->limit_callbacks_after_prio = 1;
	}
	if (cfg && cfg->max_dispatch_callbacks >= 0) {
		base->max_dispatch_callbacks = cfg->max_dispatch_callbacks;
	} else {
		base->max_dispatch_callbacks = INT_MAX;
	}
	if (base->max_dispatch_callbacks == INT_MAX &&
	    base->max_dispatch_time.tv_sec == -1)
		base->limit_callbacks_after_prio = INT_MAX;

	// 在这里确定base使用哪种IO复用模型
	// eventops 中存储了所有的IO复用模型,遍历这些模型
	for (i = 0; eventops[i] && !base->evbase; i++) {
		if (cfg != NULL) {
			/* determine if this backend should be avoided */
			// 判断是否处于被avoid的队列中
			if (event_config_is_avoided_method(cfg,
				eventops[i]->name))
				continue;
			//判断当前模型具有的features和我们提供的features是否匹配
			if ((eventops[i]->features & cfg->require_features)
			    != cfg->require_features)
				continue;
		}

		/* also obey the environment variables */
		if (should_check_environment &&
		    event_is_method_disabled(eventops[i]->name))
			continue;
		// 如果满足了所有条件就可以确定当前的IO多路复用模型
		base->evsel = eventops[i];
		// 调用多路复用函数的init函数
		base->evbase = base->evsel->init(base);
	}

	if (base->evbase == NULL) {
		event_warnx("%s: no event mechanism available",
		    __func__);
		base->evsel = NULL;
		event_base_free(base);
		return NULL;
	}

	if (evutil_getenv_("EVENT_SHOW_METHOD"))
		event_msgx("libevent using: %s", base->evsel->name);

	/* allocate a single active event queue */
	// 默认状态下base的优先级数只有1级,在这个base下面创建的event的优先级是 1/2 = 0
	if (event_base_priority_init(base, 1) < 0) {
		event_base_free(base);
		return NULL;
	}

	/* prepare for threading */

#if !defined(EVENT__DISABLE_THREAD_SUPPORT) && !defined(EVENT__DISABLE_DEBUG_MODE)
	event_debug_created_threadable_ctx_ = 1;
#endif

#ifndef EVENT__DISABLE_THREAD_SUPPORT
	if (EVTHREAD_LOCKING_ENABLED() &&
	    (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) {
		int r;
		EVTHREAD_ALLOC_LOCK(base->th_base_lock, 0);
		EVTHREAD_ALLOC_COND(base->current_event_cond);
		r = evthread_make_base_notifiable(base);
		if (r<0) {
			event_warnx("%s: Unable to make base notifiable.", __func__);
			event_base_free(base);
			return NULL;
		}
	}
#endif

#ifdef _WIN32
	if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP))
		event_base_start_iocp_(base, cfg->n_cpus_hint);
#endif

	return (base);
}


// 设置base的优先级有几级,范围在0~npriorities-1之间,数值越小优先级越高
int event_base_priority_init(struct event_base *base, int npriorities)
{
	int i, r;
	r = -1;
	// 操作base的时候要先上锁
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
	// N_ACTIVE_CALLBACKS 说明,这个函数要在event_base_dispatch之前调用
	// 然后对npriorities的范围进行了限制,最大是EVENT_MAX_PRIORITIES - 1 = 255
	if (N_ACTIVE_CALLBACKS(base) || npriorities < 1
	    || npriorities >= EVENT_MAX_PRIORITIES)
		goto err;
	// 如果之前的优先级和现在是相等的就没必要设置了
	if (npriorities == base->nactivequeues)
		goto ok;
	// 那么满足条件就进行优先级数的修改
	if (base->nactivequeues) {
		// 先释放之前的activequeues数组,每一个元素都是同等优先级的任务队列
		mm_free(base->activequeues);
		base->nactivequeues = 0;
	}

	/* Allocate our priority queues */
	// 为新的优先级队列申请空间
	base->activequeues = (struct evcallback_list *)
	  mm_calloc(npriorities, sizeof(struct evcallback_list));
	if (base->activequeues == NULL) {
		event_warn("%s: calloc", __func__);
		goto err;
	}
	// 重新设置优先级数
	base->nactivequeues = npriorities;

	// 初始化优先级队列
	for (i = 0; i < base->nactivequeues; ++i) {
		TAILQ_INIT(&base->activequeues[i]);
	}

ok:
	r = 0;
err:
	EVBASE_RELEASE_LOCK(base, th_base_lock);
	return (r);
}



// 得到当前base的优先级数,也就是返回nactivequeues
int
event_base_get_npriorities(struct event_base *base)
{

	int n;
	if (base == NULL)
		base = current_base;

	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
	n = base->nactivequeues;
	EVBASE_RELEASE_LOCK(base, th_base_lock);
	return (n);
}





// 设置config中的flag
int
event_config_set_flag(struct event_config *cfg, int flag)
{
	if (!cfg)
		return -1;
	cfg->flags |= flag;
	return 0;
}

// 可以设置的flag为:

// 生成的base具有的特征
enum event_base_config_flag {
	
   //不要为base分配锁,设置这个选项可以为base节省一点加锁和解锁的时间
   // 但是如果在多线程中访问的时候可能会出错
   EVENT_BASE_FLAG_NOLOCK = 0x01,
	
   // 选择IO多路复用函数的时候,不要去检测 EVENT_* 变量   
   EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
	
   // 仅仅适用于windows,设置了之后那么evconn_listener_new和bufferevent_socket_new函数的内部将使用IOCP
   EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,
	
   // 没有cache时间, 不是在每次事件循环中都要检测当前时间
   // 而是在每次回调后才检测
   // 一般情况下如果cache中有时间就用cache中的
   // 没有时间会使用系统调用获取时间
   EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,


   // 这个标志仅仅在epoll下有用
   // 设置了这个标志后。epoll会使用更快的基于changelist 的多路IO复用函数
   // changelist 可以在多次修改同一fd的情况下避免不必要的系统调用
   EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,

   // 通常情况下我们使用的是更快的计数器,如果设置了这个标志的话我们
   // 会使用更精确的时间
   EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
};


// 配置config具有的特征
int
event_config_require_features(struct event_config *cfg,
    int features)
{
	if (!cfg)
		return (-1);
	cfg->require_features = features;
	return (0);
}

// 可以具有的特征为

enum event_method_feature {
    EV_FEATURE_ET = 0x01,   // 支持边缘触发
    
    // 要求事件的添加,删除,触发激活等的事件复杂度是O(1),其中select and poll的时间复杂度
    // 是O(N),不满足。只有epoll支持
    EV_FEATURE_O1 = 0x02,
    
    // 要求支持任意的文件描述符,而不能仅仅支持socket
    EV_FEATURE_FDS = 0x04,
    
    // 要求可以使用EV_CLOSED来检测链接的关闭, 而不需要读取所有的未决数据才能判断
    EV_FEATURE_EARLY_CLOSE = 0x08
};

// 设置CPU的个数
int
event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)
{
	if (!cfg)
		return (-1);
	cfg->n_cpus_hint = cpus;
	return (0);
}

// 查看当前的网络模型
const char *
event_base_get_method(const struct event_base *base)
{
	EVUTIL_ASSERT(base);
	return (base->evsel->name);
}


// 查看当前IO多路复用模型具有的features
int
event_base_get_features(const struct event_base *base)
{
	return base->evsel->features;
}



// 配置需要避开的IO复用模型
int
event_config_avoid_method(struct event_config *cfg, const char *method)
{
	struct event_config_entry *entry = mm_malloc(sizeof(*entry));
	if (entry == NULL)
		return (-1);

	if ((entry->avoid_method = mm_strdup(method)) == NULL) {
		mm_free(entry);
		return (-1);
	}
        
        // 加入到 event_config 的第一个队列中
	TAILQ_INSERT_TAIL(&cfg->entries, entry, next);

	return (0);
}

 


// 得到当前os支持的所有多路复用模型
const char **
event_get_supported_methods(void)
{
	static const char **methods = NULL;
	const struct eventop **method;
	const char **tmp;
	int i = 0, k;

	/* count all methods */
	for (method = &eventops[0]; *method != NULL; ++method) {
		++i;
	}

	/* allocate one more than we need for the NULL pointer */
	tmp = mm_calloc((i + 1), sizeof(char *));
	if (tmp == NULL)
		return (NULL);

	/* populate the array with the supported methods */
	for (k = 0, i = 0; eventops[k] != NULL; ++k) {
		tmp[i++] = eventops[k]->name;
	}
	tmp[i] = NULL;

	if (methods != NULL)
		mm_free((char**)methods);

	methods = tmp;

	return (methods);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值