DELAY INIT 延迟初始化

全局变量,全局对象初始化,很方便。但过多的全局初始化,会导致程序启动时间过慢,还有全局初始化顺序不好控制(连接器可以可以控制文件之间的顺序,但那需要写好makefile, 并放映程序的实际依赖,没做到DRY).

 

我使用了内核的list_head 结构了组织初始化函数, 每个文件有一个file_node的结构来保持本文件内的初始化函数,file_node会注册的全局的一个分级数组中, file_node有个depend链表,保持了这个文件要依赖的其它文件。这样就实现了程序初始化顺序的管理。

 

delay_init.h

#ifndef __DELAY_INIT_H__
#define __DELAY_INIT_H__

#include "list.h"

namespace delay_init {
typedef int (*callback)(void);

struct file_node {
    char const *file_name;
    int called;
    list_head init_list;
    list_head depend_list;
    list_head link_to_root;
};

#define DELAY_INIT_FILE_NODE_INIT(name) \
        {\
            __BASE_FILE__,\
            0,\
            LIST_HEAD_INIT(name.init_list),\
            LIST_HEAD_INIT(name.depend_list),\
            LIST_HEAD_INIT(name.link_to_root)\
        }

#define DELAY_INIT_FILE_NODE(name)     delay_init::file_node name = DELAY_INIT_FILE_NODE_INIT(name)

struct delay_init_struct {
    list_head link_to_file;
    callback init;
    char const *info;
    int called;
};
#define DELAY_INIT_STRUCT_INIT(name) \
        {LIST_HEAD_INIT(name.link_to_file), 0, 0, 0}

#define DELAY_INIT_STRUCT(name)  delay_init::delay_init_struct name=DELAY_INIT_STRUCT_INIT(name)

struct delay_init_depend_struct {
    list_head link_to_depend;
    file_node **point_file_node;
};

#define DELAY_INIT_DEPEND_STRUCT_INIT(name)\
        {LIST_HEAD_INIT(name.link_to_depend), 0}

#define DELAY_INIT_DEPEND_STRUCT(name)  delay_init::delay_init_depend_struct name = DELAY_INIT_DEPEND_STRUCT_INIT(name)

#define INIT_LEVEL_NUM 10
#define INIT_LOG_LEVEL 3
#define INIT_CONF_LEVEL 2
#define INIT_CONF_IOC_LEVEL 1
#define INIT_FIRST_LEVEL 0
#define INIT_LAST_LEVEL (INIT_LEVEL_NUM-1)

extern list_head g_delay_init_list_head[INIT_LEVEL_NUM];

int call_all_level();

int call_in_level(int level);

extern int failed_cnt;
extern int success_cnt;
extern int total_cnt;
extern int called_cnt;
}

#define MACRO_NAME_CONCAT2(a,b) MACRO_NAME_CONCAT2_PRITIVE(a,b)
#define MACRO_NAME_CONCAT2_PRITIVE(a,b) a##b
#define STRING_NAME(name) STRING_NAME_IMPL(name)
#define STRING_NAME_IMPL(name) #name

inline
int __one_call_call_fun__(void(*fun)(void)) {
    fun();
    return 1;
}
#define ONCE_CALL_FUNC(name) MACRO_NAME_CONCAT2(__func_once_call_ ,name)
#define ONCE_CALL_VAR(name) MACRO_NAME_CONCAT2(__var_once_call_, name)
#define ONCE_CALL_WITH(name) \
         static void ONCE_CALL_FUNC(name)(void); \
         static int ONCE_CALL_VAR(name) = __one_call_call_fun__(&ONCE_CALL_FUNC(name)); \
         static void ONCE_CALL_FUNC(name)(void)

#define ONCE_CALL ONCE_CALL_WITH(MACRO_NAME_CONCAT2(__COUNTER__,__LINE__))

static DELAY_INIT_FILE_NODE(_this_file_node_delay_init_);

ONCE_CALL_WITH(delay_init_add_file_to_root)
{
    list_add_tail(&_this_file_node_delay_init_.link_to_root,
            &delay_init::g_delay_init_list_head[INIT_LAST_LEVEL]);
}

#define DELAY_INIT_IN_LEVEL(level) \
ONCE_CALL \
{\
    list_move_tail(&_this_file_node_delay_init_.link_to_root, &delay_init::g_delay_init_list_head[level]);\
}

#define DELAY_INIT_NAME(name) MACRO_NAME_CONCAT2(MACRO_NAME_CONCAT2(__delay_init_def_, name), __LINE__)
#define DELAY_INIT \
         static int DELAY_INIT_NAME(init_fun)(void); \
         static DELAY_INIT_STRUCT(DELAY_INIT_NAME(init_node));\
         ONCE_CALL { \
             DELAY_INIT_NAME(init_node).init =&DELAY_INIT_NAME(init_fun);\
             DELAY_INIT_NAME(init_node).info = \
                "delay init name:" __FILE__ "_" STRING_NAME(__LINE__)\
                " call in:" __FILE__ " line:" STRING_NAME(__LINE__); \
            list_add_tail(&DELAY_INIT_NAME(init_node).link_to_file, &_this_file_node_delay_init_.init_list);\
             return ;\
        }\
        static int DELAY_INIT_NAME(init_fun)(void)

#define DELAY_INIT_EXPORT_NAME(name) MACRO_NAME_CONCAT2(__delay_init_export_name_, name)

#define DELAY_INIT_EXPORT(name) \
        delay_init::file_node * DELAY_INIT_EXPORT_NAME(name) = & _this_file_node_delay_init_;

#define DEPEND_ON_DELAY_INIT_NAME(name) MACRO_NAME_CONCAT2(name, MACRO_NAME_CONCAT2(__delay_init_depend_struct_, __LINE__))

#define DEPEND_ON_DELAY_INIT(name)\
        extern delay_init::file_node * DELAY_INIT_EXPORT_NAME(name);\
        static DELAY_INIT_DEPEND_STRUCT(DEPEND_ON_DELAY_INIT_NAME(_struct_));\
        ONCE_CALL {\
            DEPEND_ON_DELAY_INIT_NAME(_struct_).point_file_node = &DELAY_INIT_EXPORT_NAME(name);\
            list_add_tail(&DEPEND_ON_DELAY_INIT_NAME(_struct_).link_to_depend, &_this_file_node_delay_init_.depend_list);\
        }

#endif //__DELAY_INIT_H__

 

delay_init.cpp

#include "delay_init.h"
#include "repeat_macro.h"
#ifndef LOG
#define ENABLE_DELAY_INIT_CPP_LOG
#include <stdio.h>
#define LOG(level, format, ...)\
    fprintf(stderr, "[%s][%s][%d]: " format "\n", #level, __FILE__, int(__LINE__), ##__VA_ARGS__)
#endif //LOG
namespace delay_init {

int failed_cnt = 0;
int success_cnt = 0;
int total_cnt = 0;
int called_cnt = 0;
#define INIT_LIST_HEAD_IMPL(s, index, name) COMMA_IF(index) LIST_HEAD_INIT(name[index])
#define LIST_HEAD_ARRAY_INIT(name, n) { EXPR(0)(REPEAT(0, n, INIT_LIST_HEAD_IMPL, name)) }
#define LIST_HEAD_ARRAY(name, n) list_head name[n] =  LIST_HEAD_ARRAY_INIT(name, n)
LIST_HEAD_ARRAY(g_delay_init_list_head, INIT_LEVEL_NUM);

static int call_file_list(file_node *file_list) {
    if (file_list->called) {
        return 0;
    }
    LOG(DEBUG, "delay_init in file: %s", file_list->file_name);
    int ret = 0;
    list_head *q = NULL;
    list_for_each(q, &file_list->depend_list) {
        delay_init_depend_struct *depend =
                container_of(q, delay_init_depend_struct, link_to_depend);
        if (*(depend->point_file_node)) {
            ret += call_file_list(*(depend->point_file_node));
        }
    }

    list_for_each(q, &file_list->init_list) {
        delay_init_struct *st =
                container_of(q, delay_init_struct, link_to_file);
        callback init = st->init;
        if (init) {
            if (0 == st->called) {
                LOG(DEBUG, "call delay init func:%s", st->info);
                ret += init();
                ++st->called;
                ++called_cnt;
            }
            ++success_cnt;
        } else {
            ++failed_cnt;
        }
        ++total_cnt;
    }
    ++(file_list->called);
    return ret;
}

int call_in_level(int level) {
    if (level < 0 || INIT_LEVEL_NUM - 1 < level) {
        LOG(ERROR, "error init level [%d] group", level);
        return -1;
    }LOG(DEBUG, "delay_init in level: %d", level);
    int ret = 0;
    list_head *q = NULL;
    list_for_each(q, &g_delay_init_list_head[level]) {
        file_node * file_list = container_of(q, file_node, link_to_root);
        ret += call_file_list(file_list);
    }
    return ret;
}

int call_all_level() {
    int ret = 0;
    for (int i = 0; i < INIT_LEVEL_NUM; ++i) {
        ret += call_in_level(i);
    }
    return ret;
}

}

#ifdef ENABLE_DELAY_INIT_CPP_LOG
#undef LOG
#undef ENABLE_DELAY_INIT_CPP_LOG
#endif //ENABLE_DELAY_INIT_CPP_LOG

 

使用范例

 

log.h

#ifndef __LOG_IMPL__

DEPEND_ON_DELAY_INIT(log)

#endif //__LOG_IMPL__

 

这样,所有使用了 log.h的程序,都会先初始化好log

 

log.cpp

#define __LOG_IMPL__

#include "log.h"

…….
DELAY_INIT

{

……

}


DELAY_INIT_EXPORT(log)

main.cpp

delay_init::call_all_level();

你可能感兴趣的:(init)