文章目录
1、 dpdk源码分析(一)
部分初始化由 glibc 的 start 函数完成。在初始化时还会进行检查,以确保 CPU 支持在配置文件中选择的微架构类型。然后,调用 main() 函数。核心初始化和启动在 rte_eal_init() 中完成。本章分析的是start与main之间的函数
全局变量初始化
static struct rte_tailq_elem rte_mempool_tailq = {
.name = "RTE_MEMPOOL",
};
EAL_REGISTER_TAILQ(rte_mempool_tailq)
其中EAL_REGISTER_TAILQ
宏执行了一个函数,下面将进行分析
#define EAL_REGISTER_TAILQ(t) \
RTE_INIT(tailqinitfn_ ##t) \
{ \
if (rte_eal_tailq_register(&t) < 0) \
rte_panic("Cannot initialize tailq: %s\n", t.name); \
}
可见EAL_REGISTER_TAILQ
宏展开后会有一个rte_eal_tailq_register
函数
#define RTE_PRIORITY_LOG 101
#define RTE_PRIORITY_BUS 110
#define RTE_PRIORITY_CLASS 120
#define RTE_PRIORITY_LAST 65535
#define RTE_PRIO(prio) \
RTE_PRIORITY_ ## prio
/**
* Run function before main() with high priority.
*
* @param func
* Constructor function.
* @param prio
* Priority number must be above 100.
* Lowest number is the first to run.
*/
// 调用func
#ifndef RTE_INIT_PRIO /* Allow to override from EAL */
#define RTE_INIT_PRIO(func, prio) \
static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
#endif
/**
* Run function before main() with low priority.
*
* The constructor will be run after prioritized constructors.
*
* @param func
* Constructor function.
*/
#define RTE_INIT(func) \
RTE_INIT_PRIO(func, LAST)
rte_eal_tailq_register
函数会被__attribute__((constructor))
机制执行。
下面分析rte_eal_tailq_register
函数
// 该宏TAILQ_HEAD被替换成一下begin TAILQ_HEAD(rte_tailq_elem_head, rte_tailq_elem);
struct rte_tailq_elem_head { struct rte_tailq_elem *tqh_first; struct rte_tailq_elem **tqh_last; TRACEBUF }
// 该宏TAILQ_HEAD被替换成一下end
/* local tailq list */
static struct rte_tailq_elem_head rte_tailq_elem_head =
TAILQ_HEAD_INITIALIZER(rte_tailq_elem_head);
/* local register, used to store "early" tailqs before rte_eal_init() and to
* ensure secondary process only registers tailqs once. */
static int rte_eal_tailq_local_register(struct rte_tailq_elem *t)
{
struct rte_tailq_elem *temp;
// 遍历查找
TAILQ_FOREACH(temp, &rte_tailq_elem_head, next) {
if (!strncmp(t->name, temp->name, sizeof(temp->name)))
return -1;
}
// 插入elem
TAILQ_INSERT_TAIL(&rte_tailq_elem_head, t, next);
return 0;
}
static void rte_eal_tailq_update(struct rte_tailq_elem *t)
{
// 该函数在该阶段还无法确定进程类型
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
/* primary process is the only one that creates */
t->head = rte_eal_tailq_create(t->name);
} else {
t->head = rte_eal_tailq_lookup(t->name);
}
}
int rte_eal_tailq_register(struct rte_tailq_elem *t)
{
// 校验是否已经被注册过 然后插入本进程的局部变量之中
if (rte_eal_tailq_local_register(t) < 0) {
RTE_LOG(ERR, EAL,
"%s tailq is already registered\n", t->name);
goto error;
}
/* if a register happens after rte_eal_tailqs_init(), then we can update
* tailq head */
// 注册在rte_eal_tailqs_init之后注册则进行更新
if (rte_tailqs_count >= 0) {
rte_eal_tailq_update(t);
if (t->head == NULL) {
RTE_LOG(ERR, EAL,
"Cannot initialize tailq: %s\n", t->name);
TAILQ_REMOVE(&rte_tailq_elem_head, t, next);
goto error;
}
}
return 0;
error:
t->head = NULL;
return -1;
}
如下图所示
当然还有其他的一些进行了初始化。其余的都类似,使用了attribute(constructor)
可将void*指向的data是实际数据。下面将进行对rte_eal_init()函数分析,但这个比较复杂,因此先缓一缓。