spdk初始化流程(24.05版本)

        以spdk的vhost为例,介绍spdk进程启动到执行工作的整个流程。代码目录spdk/app/存放着各种类型app的入口文件,vhost.c中的main代表vhost类型的进程初始化入口。spdk进程的大体初始化流程如下:

--->main
    --->spdk_app_opts_init
    --->spdk_app_parse_args
    --->spdk_app_start
        --->spdk_reactors_init
        --->spdk_thread_send_msg(xx, bootstrap_fn, NULL);
        --->spdk_reactors_start 
            --->reactor_run  通过while(1) 方式不停执行_reactor_run
                --->_reactor_run
            

        首先进程从main入口进入之后需要初始化参数以及入参进行解析,初始化参数在spdk_app_opts_init接口中,主要是内存地址,socket句柄,文件打印等级,rpc通信句柄地址等基本信息尽心填充。 spdk_app_parse_args接口中对入参进行解析,并且会覆盖掉一部分已经初始化的参数。

        spdk_app_start为核心内容初始化,主要初始化内容分布在以下几个接口中:

        1. spdk_reactors_init接口主要为轮训运行前的初始化,比如:调用dpdk接口spdk_mempool_create对内存池进行初始化;通过spdk_thread_lib_init_ext接口事件通知机制的线程池;通过reactor_construct接口创建轮训事件的ring环。

        2. 通过发送消息调用到bootstrap_fn(异步执行),bootstrap_fn中会在接口subsystem_sort中对各个子系统进行的依赖关系进行排序,然后根据依赖关系进行初始化;初始化的具体调用在spdk_subsystem_init_next接口中,初始入参为0,首先从链表g_subsystems中取出第一个子系统,然后当第一个子系统初始化完之后,会再次递归调用到spdk_subsystem_init_next接口(以bdev模块为例,当bdev子系统完成初始化之后会调用到bdev_initialize_complete, 该接口中会调用到spdk_subsystem_init_next,继续对下一个子系统进行初始化),直到所有子系统都初始化完成才退出。

void
spdk_subsystem_init_next(int rc)
{
	if (!g_next_subsystem) {
		g_next_subsystem = TAILQ_FIRST(&g_subsystems); //第一次进接口是获取第一个子系统
	} else {
		g_next_subsystem = TAILQ_NEXT(g_next_subsystem, tailq);
	}

	if (!g_next_subsystem) { //子系统为NULL时说明链表遍历完,都已经初始化完成
		g_subsystems_initialized = true;
		g_subsystem_start_fn(0, g_subsystem_start_arg);
		return;
	}

	if (g_next_subsystem->init) {
		g_next_subsystem->init();   //回调到各个子系统的初始化函数中
	} else {
		spdk_subsystem_init_next(0);
	}
}


// 以bdev子系统为例
static void
bdev_initialize_complete(void *cb_arg, int rc)
{
	spdk_subsystem_init_next(rc); //bdev子系统初始化完成之后再调用到改接口中,递归调用
}

static void
bdev_subsystem_initialize(void)
{
	spdk_bdev_initialize(bdev_initialize_complete, NULL); //将初始化完成的接口注册
}

bootstrap_fn中还对rpc子系统的进行了初始化。

        3. spdk_reactors_start为轮训的最终调用终点,该接口中会为每个核抛出一个reactor_run接口,每个核的reactor_run接口中进行轮训,无异常的情况下,每次都轮训一遍_reactor_run接口。

_reactor_run接口每次又会轮训一遍该核上的线程。到此,spdk的初始化彻底完成。

_reactor_run(struct spdk_reactor *reactor)
{
	if (spdk_unlikely(TAILQ_EMPTY(&reactor->threads))) { //当前任务为空,立即退出
		now = spdk_get_ticks();
		reactor->idle_tsc += now - reactor->tsc_last;
		reactor->tsc_last = now;
		return;
	}

	TAILQ_FOREACH_SAFE(lw_thread, &reactor->threads, link, tmp) {   //thread中有任务,便开始工作
		thread = spdk_thread_get_from_ctx(lw_thread);
		rc = spdk_thread_poll(thread, 0, reactor->tsc_last);

		now = spdk_thread_get_last_tsc(thread);
		if (rc == 0) {
			reactor->idle_tsc += now - reactor->tsc_last;
		} else if (rc > 0) {
			reactor->busy_tsc += now - reactor->tsc_last;
		}
		reactor->tsc_last = now;

		reactor_post_process_lw_thread(reactor, lw_thread);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值