Libevent-2.1.8源码分析——event_base(二)
2017-09-20 21:47
483 查看
1. 简介
上一节中,我们学习了如何创建一个默认的event_base。但是在实际的应用中,默认的event_base是远远满足不了需求的。更多的时候我们是需要根据具体的使用情况,来建立一个复杂的event_base。关于如何建立复杂的event_base,其实在上一篇章中,我们已经提及。接下来我们将更深入的了解如何建立一个复杂的event_base。2. event_base_new_with_config
建立一个复杂的event_base需要将设置好的event_config传递给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 //调用内存管理函数分配event_base结构 if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) { event_warn("%s: calloc", __func__); return NULL; } if (cfg) base->flags = cfg->flags; //设置flags标志 //判断是否需要检查EVENT_ * 环境变量 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; //获取环境变量 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; //初始化socketpair,用于唤醒event_base通过其他线程 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; //下面的这操作用于根据event_config进行设定 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; //选择使用的后端方法 for (i = 0; eventops[i] && !base->evbase; i++) { //根据event_config的配置,是否屏蔽某些后端或设置某项特征 if (cfg != NULL) { /* determine if this backend should be avoided */ if (event_config_is_avoided_method(cfg, eventops[i]->name)) continue; 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; //找到要使用的后端 base->evsel = eventops[i]; 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; } if (evutil_getenv_("EVENT_SHOW_METHOD")) event_msgx("libevent using: %s", base->evsel->name); /* allocate a single active event queue */ 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); }
2.1 evutil_configure_monotonic_time_
这个函数是用来配置使用时间精度精准或比较粗糙。通过是否设置了使用精准的时间标志选择。int evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base, int flags) { /* CLOCK_MONOTONIC exists on FreeBSD, Linux, and Solaris. You need to * check for it at runtime, because some older kernel versions won't * have it working. */ #ifdef CLOCK_MONOTONIC_COARSE //内核是否支持CLOCK_MONOTONIC_COARSE const int precise = flags & EV_MONOT_PRECISE; #endif const int fallback = flags & EV_MONOT_FALLBACK; struct timespec ts; #ifdef CLOCK_MONOTONIC_COARSE //关于CLOCK_MONOTONIC_COARSE和POSIX中CLOCK_MONOTONIC类似,只不过是精度比较粗糙的版本 if (CLOCK_MONOTONIC_COARSE < 0) { /* Technically speaking, nothing keeps CLOCK_* from being * negative (as far as I know). This check and the one below * make sure that it's safe for us to use -1 as an "unset" * value. */ event_errx(1,"I didn't expect CLOCK_MONOTONIC_COARSE to be < 0"); } //如果flag设置使用精准的时间,那么是不会调用下面的 if (! precise && ! fallback) { if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0) { base->monotonic_clock = CLOCK_MONOTONIC_COARSE; return 0; } } #endif //CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响,方便用于两个事件的间隔 if (!fallback && clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { base->monotonic_clock = CLOCK_MONOTONIC; return 0; } if (CLOCK_MONOTONIC < 0) { event_errx(1,"I didn't expect CLOCK_MONOTONIC to be < 0"); } base->monotonic_clock = -1; return 0; }
2.2 gettime
这个函数用于获取一个timeval时间/** Set 'tp' to the current time according to 'base'. We must hold the lock * on 'base'. If there is a cached time, return it. Otherwise, use * clock_gettime or gettimeofday as appropriate to find out the right time. * Return 0 on success, -1 on failure. */ static int gettime(struct event_base *base, struct timeval *tp) { //如果使能调试锁,那么会断言event_base是否持有锁,这边要求必须持有锁,没有则断言失败 EVENT_BASE_ASSERT_LOCKED(base); //如果时间有了缓存,直接返回。避免过多的时间获取调用 if (base->tv_cache.tv_sec) { *tp = base->tv_cache; return (0); } //会根据evutil_configure_monotonic_time_中设置的monotonic_clock 来选择是否 //使用gettimeofday或clock_gettime获取得到tp if (evutil_gettime_monotonic_(&base->monotonic_timer, tp) == -1) { return -1; } //宏CLOCK_SYNC_INTERVAL定义为5,这里的意思是5s更新一次libevent内部时间不同(可能使用gettimeofday或clock_gettime) if (base->last_updated_clock_diff + CLOCK_SYNC_INTERVAL < tp->tv_sec) { struct timeval tv; evutil_gettimeofday(&tv,NULL); evutil_timersub(&tv, tp, &base->tv_clock_diff); base->last_updated_clock_diff = tp->tv_sec; } return 0; }
3. 使用范例
#include <stdio.h> #include <string.h> #include <event2/event-config.h> #include <event2/event.h> //cc -I/usr/local/include -o test main.cpp -L/usr/local/lib -levent int main(void) { struct event_base *pBase; struct event_config *pConfig; pConfig = event_config_new(); //设置event_base_config_flag:不检测环境变量和使用更精准的定时器 event_config_set_flag(pConfig, EVENT_BASE_FLAG_IGNORE_ENV | EVENT_BASE_FLAG_PRECISE_TIMER); //告诉event_base不使用epoll和poll后端方法 event_config_avoid_method(pConfig, "epoll"); event_config_avoid_method(pConfig, "poll"); //对后端的特性进行筛选 event_config_require_features(pConfig, EV_FEATURE_FDS); //设置CPU数 event_config_set_num_cpus_hint(pConfig, 1); //设置事件优先级相关的 event_config_set_max_dispatch_interval(pConfig, NULL, -1, 0); pBase = event_base_new_with_config(pConfig); if (pBase == NULL) { fprintf(stderr, "event_base_new_with_config error!\r\n"); event_config_free(pConfig); return 0; } const char *pCurrMethod = event_base_get_method(pBase); if (pCurrMethod != NULL) printf("Current method is %s\r\n", pCurrMethod); //do something... event_config_free(pConfig); event_base_dispatch(pBase); event_base_free(pBase); return 0; }在Linux上运行如下所示:
Current method is select
相关文章推荐
- libevent源码分析(3)--2.1.8--结构体struct event_base和struct eventop
- libevent源码分析(6)--2.1.8--创建和释放libevent句柄event_base的相关函数
- Libevent-2.1.8源码分析——event_base(一)
- [libevent源码分析] event_base_dispatch
- Libevent源码分析-----配置event_base
- libevent源码分析(2)--2.1.8--结构体 struct event和struct event_callback
- Libevent源码分析-----配置event_base
- libevent源码分析(4)--2.1.8--结构体struct event_config
- Libevent源码分析—event_base_dispatch()
- Libevent源码分析-event_base
- libevent源码分析(5)--2.1.8--libevent配置信息对象struct event_config的申请和释放函数分析
- Libevent源码分析-----配置event_base
- Libevent源码分析-----配置event_base
- Libevent源码分析—event, event_base
- [libevent源码分析] event_base_dispatch
- Libevent源码分析-----配置event_base
- libevent源码分析(8)--2.1.8--事件申请与释放
- 【libevent】源码分析(4)--与event相关的一些函数和操作
- Libevent源码分析-----event_io_map哈希表
- Wangle源码分析:EventBaseHandler、AsyncSocketHandler