您的位置:首页 > 其它

libevent源码分析(5)--2.1.8--libevent配置信息对象struct event_config的申请和释放函数分析

2017-05-26 19:45 1766 查看
一、配置对象申请

配置申请是创建event_config对象并赋初值,下面看一下源码

/**
Allocates a new event configuration object.
The event configuration object can be used to change the behavior of
an event base.
@return an event_config object that can be used to store configuration, or
NULL if an error is encountered.
@see event_base_new_with_config(), event_config_free(), event_config
*/
// 分配新的event_config对象。event_config对象用来改变event_base的行为。
// 返回event_config对象,里面存放着配置信息,失败则返回NULL
// 相关查看event_base_new_with_config,event_config_free,event_config结构体等
struct event_config *
event_config_new(void)
{
// 使用内部分配api mm_calloc分配event_config对象,并赋初值1
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;
// 设置最大调度回调函数个数,初始值为int的最大值
cfg->max_dispatch_callbacks = INT_MAX;
// 设置优先级后的回调函数的限制,初始值为1
cfg->limit_callbacks_after_prio = 1;

// 由于初始分配时赋初值为1,经过上述显式设置之后,还有几个字段的初始值是1
// 查看event_config定义发现,还有三个字段使用的初始赋值:
// n_cpus_hint = 1
// require_features = 1,查看后台方法特征宏定义,发现是边沿触发方式
// flags = 1,查看event_base支持的模式,发现是非阻塞模式

return (cfg);
}


二、配置对象释放

配置对象释放和配置申请是配对使用的

/**
Deallocates all memory associated with an event configuration object
@param cfg the event configuration object to be freed.
*/
// 释放event_config对象的所有内存,和event_config_new配对使用
void
event_config_free(struct event_config *cfg)
{
struct event_config_entry *entry;

// 遍历屏蔽的后台方法列表,释放屏蔽的后台方法项目
while ((entry = TAILQ_FIRST(&cfg->entries)) != NULL) {
TAILQ_REMOVE(&cfg->entries, entry, next);
event_config_entry_free(entry);
}
// mm_calloc的释放程序
mm_free(cfg);
}

屏蔽的后台方法释放
// 使用内置的mm_free释放mm_calloc申请的空间
static void
event_config_entry_free(struct event_config_entry *entry)
{
if (entry->avoid_method != NULL)
mm_free((char *)entry->avoid_method);
mm_free(entry);
}


三、配置设置

如果对默认配置不满意,可以进行手动设置,以下是提供手动配置的api

有关工作模式类型可以参考事件类型标志一文:

libevent源码分析(1)--2.1.8--事件标志

1、设置event_base采用的工作模式

/**
* Sets one or more flags to configure what parts of the eventual event_base
* will be initialized, and how they'll work.
*
* @see event_base_config_flags, event_base_new_with_config()
**/
// 设置event_base的工作模式,需要在申请event_config之后运行,在配置event_base之前执行;
// 可以设置多个工作模式同时存在,但是需要注意的是不是每种工作模式都是可以设置的,
// 需要查看本地内核环境以及后台方法是否支持
int
event_config_set_flag(struct event_config *cfg, int flag)
{
if (!cfg)
return -1;
cfg->flags |= flag;
return 0;
}


2、设置后台方法的工作方式

/**
Enters a required event method feature that the application demands.
Note that not every feature or combination of features is supported
on every platform.  Code that requests features should be prepared
to handle the case where event_base_new_with_config() returns NULL, as in:
<pre>
event_config_require_features(cfg, EV_FEATURE_ET);
base = event_base_new_with_config(cfg);
if (base == NULL) {
// We can't get edge-triggered behavior here.
event_config_require_features(cfg, 0);
base = event_base_new_with_config(cfg);
}
</pre>
@param cfg the event configuration object
@param feature a bitfield of one or more event_method_feature values.
Replaces values from previous calls to this function.
@return 0 on success, -1 on failure.
@see event_method_feature, event_base_new_with_config()
*/
// 设置后台方法特征,注意不是每个平台都会支持所有特征或者支持几个特征同时存在;
// 设置后台方法特征的代码应该在event_base_new_with_config之前进行;
// 注意,这里不是采用或的方式,而是直接替换为输入的方法特征

int
event_config_require_features(struct event_config *cfg,
int features)
{
if (!cfg)
return (-1);
cfg->require_features = features;
return (0);
}


3、屏蔽某些后台方法

可以通过编译选项进行屏蔽,也可以通过以下api进行手动设置
/**
Enters an event method that should be avoided into the configuration.
This can be used to avoid event mechanisms that do not support certain
file descriptor types, or for debugging to avoid certain event
mechanisms.  An application can make use of multiple event bases to
accommodate incompatible file descriptor types.
@param cfg the event configuration object
@param method the name of the event method to avoid
@return 0 on success, -1 on failure.
*/
// 输入需要屏蔽的方法名字;可以用来避免某些不支持特定文件描述符类型的后台方法,
// 或者调试用来屏蔽某些特定事件的机制。应用可以使用多个event_bases以适应不兼容的
// 文件描述符类型。
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);
}

// 将屏蔽的方法插入屏蔽队列
TAILQ_INSERT_TAIL(&cfg->entries, entry, next);

return (0);
}


4、设置cpu个数提示信息

/**
* Records a hint for the number of CPUs in the system. This is used for
* tuning thread pools, etc, for optimal performance.  In Libevent 2.0,
* it is only on Windows, and only when IOCP is in use.
*
* @param cfg the event configuration object
* @param cpus the number of cpus
* @return 0 on success, -1 on failure.
*/
// 记录有关系统cpu个数的提示;用来调整线程池;在2.0中,只能用于windows,
// 而且只能当使用IOCP时才有效
int
event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)
{
if (!cfg)
return (-1);
cfg->n_cpus_hint = cpus;
return (0);
}


5、设置event_base调度的一些间隔信息

/**
* Record an interval and/or a number of callbacks after which the event base
* should check for new events.  By default, the event base will run as many
* events are as activated at the higest activated priority before checking
* for new events.  If you configure it by setting max_interval, it will check
* the time after each callback, and not allow more than max_interval to
* elapse before checking for new events.  If you configure it by setting
* max_callbacks to a value >= 0, it will run no more than max_callbacks
* callbacks before checking for new events.
*
* This option can decrease the latency of high-priority events, and
* avoid priority inversions where multiple low-priority events keep us from
* polling for high-priority events, but at the expense of slightly decreasing
* the throughput.  Use it with caution!
*
* @param cfg The event_base configuration object.
* @param max_interval An interval after which Libevent should stop running
*     callbacks and check for more events, or NULL if there should be
*     no such interval.
* @param max_callbacks A number of callbacks after which Libevent should
*     stop running callbacks and check for more events, or -1 if there
*     should be no such limit.
* @param min_priority A priority below which max_interval and max_callbacks
*     should not be enforced.  If this is set to 0, they are enforced
*     for events of every priority; if it's set to 1, they're enforced
*     for events of priority 1 and above, and so on.
* @return 0 on success, -1 on failure.
**/
// 记录event_base用于检查新事件的时间间隔或者回调函数个数;默认情况下,
// event_base在检查新事件之前,应当是有多少最高优先级的激活事件就执行多少这样激活的事件;
// 如果你通过max_interval设置了两次检查之间的时间间隔,它将在每次执行回调之后检查距离上一次检查新事件的
// 时间间隔是否超过了max_interval,在两次检查新事件之间不允许超过max_interval。
// 如果你通过配置max_callbacks>=0,则两次检查新事件之间不会执行超过max_callbacks个
// 回调函数。

// 这个选项可以降低高优先级事件的延迟,同时避免优先级颠倒执行,即多个低优先级事件
// 屏蔽了高优先级事件,即多个低优先级先发生,高优先级事件后发生,而event_base一直在执行低优先级事件,
// 而导致高优先级事件迟迟得不到执行,但是会轻微降低吞吐量,谨慎使用这个。

// cfg: event_config对象
// max_interval:event_base停止执行回调并检查新事件的时间间隔,如果不想设置这样的间隔,可以设置为NULL
// max_callbacks:event_base停止执行回调并检查新事件的已执行的最大回调函数个数,如果不需要,可以设置为-1
// min_priority:即低于这个值的优先级,就不应该强制执行max_interval和max_callbacks检查;如果设置为0,
// 则对每个优先级都执行这两个检查;如果设置为1,只有priority>=1时,才执行这样的检查
int
event_config_set_max_dispatch_interval(struct event_config *cfg,
const struct timeval *max_interval, int max_callbacks, int min_priority)
{
// 如果max_interval不为空,则将输入的参数拷贝到cfg中,
// 否则设置为非法值
if (max_interval)
memcpy(&cfg->max_dispatch_interval, max_interval,
sizeof(struct timeval));
else
cfg->max_dispatch_interval.tv_sec = -1;
// 如果max_callbacks >=0,则设置为max_callbacks,否则设置为INT_MAX
cfg->max_dispatch_callbacks =
max_callbacks >= 0 ? max_callbacks : INT_MAX;
// 如果<0,则所有优先级都执行检查,否则设置为传入参数
if (min_priority < 0)
min_priority = 0;
cfg->limit_callbacks_after_prio = min_priority;
return (0);
}


三、配置获取

1、获取当前正在使用的后台方法

/**
Get the kernel event notification mechanism used by Libevent.
@param eb the event_base structure returned by event_base_new()
@return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
*/
// 获取event使用的内核事件通知机制。
// base是使用event_base_new()创建的event_base句柄
const char *
event_base_get_method(const struct event_base *base)
{
EVUTIL_ASSERT(base);
return (base->evsel->name);
}


2、获取当前环境可以支持的后台方法

/**
Gets all event notification mechanisms supported by Libevent.
This functions returns the event mechanism in order preferred by
Libevent.  Note that this list will include all backends that
Libevent has compiled-in support for, and will not necessarily check
your OS to see whether it has the required resources.
@return an array with pointers to the names of support methods.
The end of the array is indicated by a NULL pointer.  If an
error is encountered NULL is returned.
*/
// 获取event_base支持的所有事件通知机制。这个函数返回libevent选择的
// 事件机制。注意,这个列表包含libevent编译时就支持的所有后台方法,
// 它不会做有关OS的必要性检查,以查看是否有必要的资源。
// 返回指针数组,每个指针指向支持方法的名字。数组的末尾指向NULL。
//
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 */
// 遍历静态全局数组eventops,获得编译后的后台方法个数
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 */
// 在tmp数组中保存名字指针
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);
}


3、获取后台方法的工作模式

/**
Return a bitmask of the features implemented by an event base.  This
will be a bitwise OR of one or more of the values of
event_method_feature
@see event_method_feature
*/
// 返回event_base后台方法的特征。可以是多个特征通过OR方法求并的结果
int
event_base_get_features(const struct event_base *base)
{
return base->evsel->features;
}


4、获取event_base的优先级个数

/**
Get the number of different event priorities.
@param eb the event_base structure returned by event_base_new()
@return Number of different event priorities
@see event_base_priority_init()
*/
// 获取不同事件优先级个数
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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  libevent