nng协议nni_posix_resolv_sysinit()系统初始化

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

源码:

cpp 复制代码
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 的类型:

cpp 复制代码
//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);

cpp 复制代码
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]。甚至我们可以通过内存对齐算一下这个值。

cpp 复制代码
//在文件/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]

初始化之后的值为:

cpp 复制代码
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的类型定义:

cpp 复制代码
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] 数组元素进行一次初始化操作,初始化之后的值是:

cpp 复制代码
&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 );

初始化后的值是:

cpp 复制代码
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列表的初始化、解析并发级别的设置、解析线程结构数组的分配以及解析线程的初始化和启动。整个过程确保解析系统能够高效地并发处理解析请求。

  1. resolv_worker的执行(待续。。。)
相关推荐
爱吃生蚝的于勒2 小时前
C语言内存函数
c语言·开发语言·数据结构·c++·学习·算法
失落的香蕉5 小时前
C语言串讲-2之指针和结构体
java·c语言·开发语言
ChoSeitaku7 小时前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表
DdddJMs__1357 小时前
C语言 | Leetcode C语言题解之第557题反转字符串中的单词III
c语言·leetcode·题解
娃娃丢没有坏心思8 小时前
C++20 概念与约束(2)—— 初识概念与约束
c语言·c++·现代c++
ahadee9 小时前
蓝桥杯每日真题 - 第11天
c语言·vscode·算法·蓝桥杯
No0d1es10 小时前
2024年9月青少年软件编程(C语言/C++)等级考试试卷(九级)
c语言·数据结构·c++·算法·青少年编程·电子学会
Che3rry11 小时前
C/C++|关于“子线程在堆中创建了资源但在资源未释放的情况下异常退出或挂掉”如何避免?
c语言·c++
kuiini12 小时前
C 语言学习-02【编程习惯】
c语言·学习
木辛木辛子12 小时前
L2-2 十二进制字符串转换成十进制整数
c语言·开发语言·数据结构·c++·算法