Libevent 源码学习笔记(2)event_base_new

目录

event_base_new

event_config

event_base_new_with_config


event_base_new

struct event_base *
event_base_new(void)
{
	struct event_base *base = NULL;                 // 初始化一个event_base 
	struct event_config *cfg = event_config_new();  // 看下文注解
	if (cfg) {
		base = event_base_new_with_config(cfg);  // 将event_config 绑定到base上
		event_config_free(cfg);                  // 资源释放
	}
	return base;
}

event_config

struct event_config_entry {
	TAILQ_ENTRY(event_config_entry) next;  // 下一个屏蔽的后台

	const char *avoid_method;  // 屏蔽的后台名字
};

struct event_config {
    // 屏蔽后台的双向队列
	TAILQ_HEAD(event_configq, event_config_entry) entries;
    // 建议的cpu数量,不强制
	int n_cpus_hint;
    // 最大调度间隔
	struct timeval max_dispatch_interval;
	int max_dispatch_callbacks;  // 事件循环中可以处理最大的回调数量
	int limit_callbacks_after_prio; // 回调函数优先级限制

    // 用于描述 event_base 提供了哪些功能的标志
    // event_config_require_features() 告诉 Libevent 仅在您的
    // event_base 实现了一个给定的特性
    // event_base_get_features() 以查看哪些功能可用
    // event_config_require_features()输入应用程序要求的必需 event 方法功能
    // EV_FEATURE_ET = 0x01, 边缘触发
    // EV_FEATURE_O1 = 0x02, O(1)事件触发 不轮询 epoll,kqueue
    // EV_FEATURE_FDS = 0x04, 可以处理包括sockets在内的各种文件描述符
    // EV_FEATURE_EARLY_CLOSE = 0x08, 可以使用EV_CLOSED检测连接关闭,不需读完所有挂起数据
	enum event_method_feature require_features;
    /*
    enum event_base_config_flag 
    {
	    // 不给这个event_base分配锁,即使有锁设定,可以省去加锁解锁消耗,但多线程下不安全
	    EVENT_BASE_FLAG_NOLOCK = 0x01,
	    // 不检查 EVENT_* 环境变量
	    EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
        // 仅对windows有效,启用Libevent时 bufferevent_socket_new() 和
        evconn_listener_new() 将使用 IOCP 支持的实现,而不是在需要时才使用
	    EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,
        // 在每个超时回调后检测当前时间,而不是在超时回调前检测
    	EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,
        // 如果使用EPOLL后端,使用change-list 是安全的,可以让代码运行更快
    	EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,
        // 使用效率低但更精准的计时器
	    EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
    };
    */
	enum event_base_config_flag flags;
};

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);
}

event_base_new_with_config

// 使用本函数初始化新的event_base,可以使用配置对象来屏蔽某些特定的时间通知
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
    
    // 申请空间并初始化 对每个域都赋值1
	if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) {
		event_warn("%s: calloc", __func__);
		return NULL;
	}

	if (cfg)   // 把传进来的参数 event_config 简单的给event_base赋个值
		base->flags = cfg->flags;

     // 赋值是否需要进行环境检查,默认情况下是没有设置EVENT_BASE_FLAG_IGNORE_ENV的
    // 所以 should_check_enviroment = 1 检查环境变量
	should_check_environment =
	    !(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));

	{    // 检查时间是否发生变化    
		struct timeval tmp; 
        // 如果使用精确时间,则precise_time = 1
		int precise_time =
		    cfg && (cfg->flags & EVENT_BASE_FLAG_PRECISE_TIMER);
		int flags;
		if (should_check_environment && !precise_time) {
            // evutil_getenv_ (getenv)获取环境变量
			precise_time = evutil_getenv_("EVENT_PRECISE_TIMER") != NULL;
			if (precise_time) {
				base->flags |= EVENT_BASE_FLAG_PRECISE_TIMER;
			}
		}

        // 默认情况下 precise_time = 1 既 flags = EV_MONOT_PRECISE 
		flags = precise_time ? EV_MONOT_PRECISE : 0;
        // 配置单调递增的时间,默认情况下,会使用EV_MONOTONIC模式获取系统时间,并将event_base的monotonic_clock模式设置为EV_MONOTONIC;
		evutil_configure_monotonic_time_(&base->monotonic_timer, flags);
        // 获取当前event_base中缓存的时间,并设置使用系统时间更新event_base缓存时间的时间间隔,并获取当前系统的monotonic时间和当前系统的real时间之间差值并存储在event_base中
		gettime(base, &tmp);
	}
    
    // 创建时间最小堆
	min_heap_ctor_(&base->timeheap);
    
    // 内部信号通知的管道 0读1写
	base->sig.ev_signal_pair[0] = -1;
	base->sig.ev_signal_pair[1] = -1;
    // 内部线程通知的文件描述符 0读1写
	base->th_notify_fd[0] = -1;
	base->th_notify_fd[1] = -1;
    // 初始化下一次激活的队列
	TAILQ_INIT(&base->active_later_queue);
    // 初始化io事件的映射
    // base->io = event_io_map
    // 如果在windows环节下,event_io_map会使用哈希结构
    // 否则当成 event_signal_map 来使用
	evmap_io_initmap_(&base->io);
    // 初始化信号到事件的映射
	evmap_signal_initmap_(&base->sigmap);
    // 初始化变化时间列表
	event_changelist_init_(&base->changelist);
    // 后端方法初始化
	base->evbase = NULL;

    // 把传进来的参数 event_config 简单的给event_base赋个值
	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的后端方法进行初始化
	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];
        // 调用相应后端方法的初始化函数进行初始化
        /* 例如epoll
        const struct eventop epollops = 
        {    
	        "epoll",
	        epoll_init, //调用此处进行初始化
	        epoll_nochangelist_add,
	        epoll_nochangelist_del,
	        epoll_dispatch,
	        epoll_dealloc,
	        1, // need reinit 
	        EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_EARLY_CLOSE,
	        0
        };
        */
		base->evbase = base->evsel->init(base);
	}
    
    // 如果没有发现能用的后端方法 释放资源后返回 NULL
	if (base->evbase == NULL) {
		event_warnx("%s: no event mechanism available",
		    __func__);          // 报错
		base->evsel = NULL;
		event_base_free(base);  // 释放资源
		return NULL;
	}
    
    // 获取环境变量 EVENT_SHOW_METHOD。打印后端方法名字
	if (evutil_getenv_("EVENT_SHOW_METHOD"))
		event_msgx("libevent using: %s", base->evsel->name);

	// 分配一个事件优先队列,初始个数为1 
	if (event_base_priority_init(base, 1) < 0) {
		event_base_free(base);
		return NULL;
	}

    // 准备线程
#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);
}

参考文章 https://blog.csdn.net/qq_34768693/article/details/119861542 Libevent 源码学习笔记(1) event 与 event_base

你可能感兴趣的:(linux,计算机网络)