全局变量,全局对象初始化,很方便。但过多的全局初始化,会导致程序启动时间过慢,还有全局初始化顺序不好控制(连接器可以可以控制文件之间的顺序,但那需要写好makefile, 并放映程序的实际依赖,没做到DRY).
我使用了内核的list_head 结构了组织初始化函数, 每个文件有一个file_node的结构来保持本文件内的初始化函数,file_node会注册的全局的一个分级数组中, file_node有个depend链表,保持了这个文件要依赖的其它文件。这样就实现了程序初始化顺序的管理。
#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) #nameinline
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__
#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
#ifndef __LOG_IMPL__
DEPEND_ON_DELAY_INIT(log)
#endif //__LOG_IMPL__
这样,所有使用了 log.h的程序,都会先初始化好log
#define __LOG_IMPL__
#include "log.h"
…….
DELAY_INIT{
……
}
DELAY_INIT_EXPORT(log)
delay_init::call_all_level();