4.2 register_driver()把mlx5_driver_init()放置到一个链表结点上
/* libibverbs-1.2.1/src/init.c#157 */
157 static void register_driver(const char *name, ibv_driver_init_func init_func,
158 verbs_driver_init_func verbs_init_func)
159 {
160 struct ibv_driver *driver;
161
162 driver = malloc(sizeof *driver);
...
168 driver->name = name;
169 driver->init_func = init_func;
170 driver->verbs_init_func = verbs_init_func;
171 driver->next = NULL;
172
173 if (tail_driver)
174 tail_driver->next = driver;
175 else
176 head_driver = driver;
177 tail_driver = driver;
178 }
L160: 定义一个类型为struct ibv_driver的结构体变量driver,该变量将作为一个链表结点。struct ibv_driver的定义如下:
/* libibverbs-1.2.1/src/init.c#70 */
70 struct ibv_driver {
71 const char *name;
72 ibv_driver_init_func init_func;
73 verbs_driver_init_func verbs_init_func;
74 struct ibv_driver *next;
75 };
L162: 为结构体变量driver申请内存空间
L168: 设置driver->name, e.g. "mlx5"
L169: 设置driver->init_func, e.g. NULL
L170: 设置driver->verbs_init_func, e.g. mlx5_driver_init
L171: 设置driver->next 为 NULL
L173-177: 维护全局链表head_driver, tail_driver可以理解为指向该链表的尾结点的指针,那么在L162申请的结点driver就是通过尾插法加入到链表head_driver中去的。
/* libibverbs-1.2.1/src/init.c#79 */
79 static struct ibv_driver *head_driver, *tail_driver;
接下来,我们需要去看看究竟是谁在消费全局链表head_driver。
4.3 消费全局链表head_driver的是try_drivers()函数
/* libibverbs-1.2.1/src/init.c#408 */
408 static struct ibv_device *try_drivers(struct ibv_sysfs_dev *sysfs_dev)
409 {
410 struct ibv_driver *driver;
411 struct ibv_device *dev;
412
413 for (driver = head_driver; driver; driver = driver->next) {
414 dev = try_driver(driver, sysfs_dev);
415 if (dev)
416 return dev;
417 }
418
419 return NULL;
420 }
在L413-417中,遍历全局链表head_driver, 针对单个结点driver在L414调用try_driver(driver, sysfs_dev)函数。如果匹配成功,则理解返回对应的ibv设备(struct