reactor线程是SPDK中负责实际业务处理逻辑的单元,它们在vhsot服务启动时创建,直到服务停止。目前还不支持reactor线程的动态增减。
reactor线程总流程
我们顺着vhost进程的代码执行顺序来看看总体流程:
spdk/app/vhost/vhost.c:
int
main(int argc, char *argv[])
{
struct spdk_app_opts opts = {};
int rc;
/* 首先进行参数解析,解析后的结果保存于opts中 */
vhost_app_opts_init(&opts);
if ((rc = spdk_app_parse_args(argc, argv, &opts, "f:S:",
vhost_parse_arg, vhost_usage)) !=
SPDK_APP_PARSE_ARGS_SUCCESS) {
exit(rc);
}
...
/* 接着根据配置文件指明的物理核启动reactors线程(主线程最终也成为一个reactor)。
这些reactors线程会执行轮循函数,直到外部将服务状态置为退出 */
/* Blocks until the application is exiting */
rc = spdk_app_start(&opts, vhost_started, NULL, NULL);
/* 所有reactor线程退出后,进行资源清理 */
spdk_app_fini();
return rc;
}
上述整体流程中最为重要的便是spdk_app_start函数,该函数内部调用了DPDK关于系统CPU、内存、PCI设备管理等通用性服务代码,这里我们尽可能以理解其功能为主而不做深入的代码分析:
spdk/lib/event/app.c:
int
spdk_app_start(struct spdk_app_opts *opts, spdk_event_fn start_fn,
void *arg1, void *arg2)
{
struct spdk_conf *config = NULL;
int rc;
struct spdk_event *app_start_event;
...
/* 将配置文件中的内容导入到config对象中 */
config = spdk_app_setup_conf(opts->config_file);
...
spdk_app_read_config_file_global_params(opts);
...
/* 调用DPDK系统服务:
(1)通过内核sysfs获取物理CPU信息,并通过配置文件指定的运行核,在各个核上启动服务线程;
各服务线程启动后因为在等待主线程给它们发送需要执行的任务而处于睡眠状态;
(2)基于大页内存创建内存池以供其它模块使用;
(3)初始化PCI设备枚举服务,可以实现类似内核的设备发现及驱动初始化流程。SPDK基于此并借
助内核uio或vfio驱动实现全用户态的PCI驱动 */