libevent源碼分析(5)--2.1.8--libevent配置信息對象struct event_config的申請和釋放函數分析

一、配置對象申請

配置申請是創建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);
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章