nni_posix_resolv_sysinit(void) 实现了一个初始化函数 nni_posix_resolv_sysinit,用于设置解析系统(resolver system)。它主要负责初始化解析线程池,用于并发处理域名解析请求。

源码:

int
nni_posix_resolv_sysinit(void)
{
	resolv_fini = false;
	nni_aio_list_init(&resolv_aios);

#ifndef NNG_RESOLV_CONCURRENCY
#define NNG_RESOLV_CONCURRENCY 4
#endif

	resolv_num_thr = (int) nni_init_get_param(
	    NNG_INIT_NUM_RESOLVER_THREADS, NNG_RESOLV_CONCURRENCY);
	if (resolv_num_thr < 1) {
		resolv_num_thr = 1;
	}
	// no limit on the maximum for now
	nni_init_set_effective(NNG_INIT_NUM_RESOLVER_THREADS, resolv_num_thr);
	resolv_thrs = NNI_ALLOC_STRUCTS(resolv_thrs, resolv_num_thr);
	if (resolv_thrs == NULL) {
		return (NNG_ENOMEM);
	}

	for (int i = 0; i < resolv_num_thr; i++) {
		int rv = nni_thr_init(&resolv_thrs[i], resolv_worker, NULL);
		if (rv != 0) {
			nni_posix_resolv_sysfini();
			return (rv);
		}
	}
	for (int i = 0; i < resolv_num_thr; i++) {
		nni_thr_run(&resolv_thrs[i]);
	}

	return (0);
}

过程分析:

1. 对全局变量resolv_aios初始化:

   这里首先贴一下resolv_aios 的类型:

//nni_list_node 的类型定义:
typedef struct nni_list_node {
	struct nni_list_node *ln_next;
	struct nni_list_node *ln_prev;
} nni_list_node;

//nni_list 的类型定义:
typedef struct nni_list {
	struct nni_list_node ll_head;
	size_t               ll_offset;
} nni_list;

//resolv_aios 的定义
static nni_list resolv_aios;

        基本流程:首先初始化全局变量 resolv_fini = false;  紧接着初始化了全局变量  resolv_aios  

这里简单插一句初始化的过程:nni_aio_list_init(&resolv_aios);

void
nni_aio_list_init(nni_list *list)
{
	NNI_LIST_INIT(list, nni_aio, a_prov_node);
}

#define NNI_LIST_INIT(list, type, field) \
	nni_list_init_offset(list, offsetof(type, field))


void
nni_list_init_offset(nni_list *list, size_t offset)
{
	list->ll_offset       = offset;
	list->ll_head.ln_next = &list->ll_head;
	list->ll_head.ln_prev = &list->ll_head;
}

简单分析一下就是,nni_aio_list_init()函数对全局变量 resolv_aios  的初始化操作。而nni_aio_list_init  的定义是一个宏:NNI_LIST_INIT,这个是通用的宏定义,其他初始化也会用到。在这个宏里,传入了3个参数:

第一个就是我们的全局变量的地址:&resolv_aios

第二个是 type类型,这里是  nni_aio 这个结构体

第三个是 a_prov_node

在宏里调用了函数 nni_list_init_offset (list,  offsetof(type,  field))这里的type就是 nni_aiofield是 a_prov_node offsetof是一个内核中常用的宏,用于计算结构体类型距离结构体首地址的偏移量。我们可以在代码中加一行计算这个值并输出:offserof aio -> a_prov_node=[408]。甚至我们可以通过内存对齐算一下这个值。

//在文件/src/platform/posix/posix_resolv_gai.c的480行添加下面的代码
printf("offserof aio -> a_prov_node=[%d]\n", offsetof(nni_aio, a_prov_node));
//我们将看到输出是 offserof aio -> a_prov_node=[408]

初始化之后的值为:

resolv_aios->ll_ofset  = 408;
resolv_aios->ll_head.ln_next = &resolv_aios->ll_head;
resolv_aios->ll_head.ln_prev = &resolv_aios->ll_head;

当然我们也可以直接在初始化完成后进行直接输出,经过验证:resolv_aios.ll_offset=[408];其实就是对全局变量 resolv_aios 的指针及 ll_offset 字段进行了初始化。结果如上。

  • resolv_fini 被设置为 false,表示解析系统还未完成。
  • nni_aio_list_init 函数初始化一个异步I/O列表 resolv_aios,用于存储待处理的解析请求。

2. 解析并发级别设置

  • 如果未定义 NNG_RESOLV_CONCURRENCY,则将其定义为 4。
  • 使用 nni_init_get_param 获取解析线程数,默认值为 NNG_RESOLV_CONCURRENCY
  • 确保解析线程数至少为 1。 

这里不做详细分析,感兴趣的同学请分析并留下链接,大家一起学习。

3. 分配解析线程结构数组

        分配  resolv_thrs 数组,大小为 resolv_num_thr ;

        分配失败则返回内存不足

4. 初始化和启动解析线程

        这里对 resolv_aios逐个(这里是4个,执行同样的操作)进行初始化。调用的函数是不是有点眼熟!nni_thr_init 。

这里的参数类型是 nni_thr (和前面一篇 nni_posix_global_pollq 初始化的成员变量是同一类型)。为方便查看,这里再次贴出nni_thr的类型定义:

struct nni_thr {
	nni_plat_thr thr;
	nni_plat_mtx mtx;
	nni_plat_cv  cv;
	nni_thr_func fn;
	void *       arg;
	int          start;
	int          stop;
	int          done;
	int          init;
};

//上面结构体的成员变量
struct nni_plat_thr {
	pthread_t tid;
	void (*func)(void *);
	void *arg;
};

在 nni_thr_init  函数中,对每个resolv_thrs[i] 数组元素进行一次初始化操作,初始化之后的值是:

&resolv_thrs[i]->done  = 0;
&resolv_thrs[i]->start = 0;
&resolv_thrs[i]->stop  = 0;
&resolv_thrs[i]->fn    = resolv_worker;
&resolv_thrs[i]->arg   = NULL;

同样,对thr->thr 也会进行初始化,执行函数nni_plat_thr_init (&thr->thr, nni_thr_wrap, thr  );

初始化后的值是:

nni_thr的成员变量 nni_plat_thr
nni_thr->nni_plat_thr->func = nni_thr_wrap;
nni_thr->nni_plat_thr->arg  = nni_thr;

接下来创建一个线程, 线程的id 就是 nni_thr->nni_plat_thr->tid,线程属性沿用了前面初始化的线程属性。 执行线程函数 nni_plat_thr_main。在线程函数中,会执行函数

nni_thr->func(nni_thr->arg);这里就执行nni_thr初始化的函数 resolv_worker,回顾上面的初始化过程可知,参数是NULL。

这段代码通过设置并发解析线程池来初始化解析系统,用于处理异步域名解析请求。初始化过程中包括全局变量和AIO列表的初始化、解析并发级别的设置、解析线程结构数组的分配以及解析线程的初始化和启动。整个过程确保解析系统能够高效地并发处理解析请求。

5. resolv_worker的执行(待续。。。)

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部