前言 国庆后这周连续上来7天班,事情做了许多,也包含了许多小事儿,大的部分暂时没有准备好。本周就拼凑着讲一下几个小事儿。
DPDK ring出队是否卡住 节前的时候,组里的同事检视我的代码,提了一个意见。说是rte_ring这个环状队列,被调用批量出队的时候,如果对内里面的个数小于期望的个数,那么会返回0或者卡住。我就写了个demo验证了一下,结果如下:
可以看出,出队时并不会卡住,即使不满足期望个数也会出队实际的个数。
动态库的constructor方法在库被加载时才会被调用 我们知道,如果设置了一个函数的gcc属性为__attribute__(constructor),那么在main函数运行之前就会调用这个函数。
同事在把DPDK的driver库编译为动态库的时候,发现运行的时候很多数据没有正常初始化。然后打印了断点,函数也没有被断到,可以确定对应的函数没有执行。
想来没有加载动态库的时候,这些函数也就在main运行之前不会被调用了,很正常。DPDK的eal参数提供了加载指定驱动的命令选项, 可以通过加载指定的so,后续在运行的时候发现数据正常初始化了。
看了一下这块的代码,
1 2 3 -d LIB.so|DIR Add a driver or driver directory (can be used multiple times)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 int eal_parse_common_option (int opt, const char *optarg, struct internal_config *conf) ... case 'd': if (eal_plugin_add(optarg) == -1 ) return -1; break ; static int eal_plugin_add (const char *path) { struct shared_driver *solib ; solib = malloc (sizeof (*solib)); if (solib == NULL ) { RTE_LOG(ERR, EAL, "malloc(solib) failed\n" ); return -1 ; } memset (solib, 0 , sizeof (*solib)); strlcpy(solib->name, path, PATH_MAX); TAILQ_INSERT_TAIL(&solib_list, solib, next); return 0 ; } int eal_plugins_init (void ) { struct shared_driver *solib = NULL ; struct stat sb ; if (is_shared_build() && *default_solib_dir != '\0' && stat(default_solib_dir, &sb) == 0 && S_ISDIR(sb.st_mode)) eal_plugin_add(default_solib_dir); TAILQ_FOREACH(solib, &solib_list, next) { if (stat(solib->name, &sb) == 0 && S_ISDIR(sb.st_mode)) { if (eal_plugindir_init(solib->name) == -1 ) { RTE_LOG(ERR, EAL, "Cannot init plugin directory %s\n" , solib->name); return -1 ; } } else { RTE_LOG(DEBUG, EAL, "open shared lib %s\n" , solib->name); solib->lib_handle = eal_dlopen(solib->name); if (solib->lib_handle == NULL ) return -1 ; } } return 0 ; }
可以看到,在参数解析的时候会把driver对应的路径存起来, 在后面的eal_plugins_init时候调用dlopen加载该动态库。 很多插件的实现原理也是类似,通过加载固定文件夹下的so,触发特定的函数执行,或者是调用so内部的特定函数,实现对应的功能。
destructor在函数异常退出是不会调用被调用 最近在设计一个用户态库的接口,需要对外提供资源的申请释放的接口,资源是通过ioctl调用内核的驱动模块来操作的,也就是多个用户态进程会共同使用内核的资源。我本来是想着,如果使用接口的进程异常退出了,那么就由用户态的库自动释放这些资源。本来我是想着使用attribute(destructor)属性的函数来实现已申请的资源的释放的。实验了一下,发现此路不同。
show you code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <stdio.h> #include <stdlib.h> __attribute__((constructor)) static void beforeFunction () { printf ("beforeFunction\n" ); } __attribute__((destructor)) static void afterFunction () { printf ("afterFunction\n" ); } void main (void ) { int i = 0 ; int times = 60 ; while (i++ < times) { printf ("current i = %d\r\n" , i); sleep(1 ); } return ; }
编译运行之后,我使用kill -9 命令杀死这个进程,可以看到,并没有输出afterFunction。
device_create创建设备文件 之前在学习驱动的时候,文章字符设备驱动 使用的mknod命令手动创建了设备文件。这周看了之前的驱动代码, 使用device_create函数创建了设备文件。
在调用device_create前要先用class_create创建一个类。类这个概念在Linux中被抽象成一种设备的集合。类在/sys/class目录中。
1 2 3 4 5 6 7 8 root@keep-VirtualBox:/sys/class# ls /sys/class/ ata_device block devlink drm_dp_aux_dev hidraw intel_scu_ipc mem net power_supply ptp remoteproc scsi_generic thermal vc watchdog ata_link bsg dma extcon hwmon iommu misc pci_bus ppdev pwm rfkill scsi_host tpm vfio wwan ata_port devcoredump dma_heap firmware i2c-adapter leds mmc_host pci_epc ppp rapidio_port rtc sound tpmrm virtio-ports backlight devfreq dmi gpio i2c-dev lirc msr phy pps rc scsi_device spi_master tty vtconsole bdi devfreq-event drm graphics input mdio_bus nd powercap printer regulator scsi_disk spi_slave usb_role wakeup root@keep-VirtualBox:/sys/class#
主要代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ... globalmem_devp->dev_class = class_create(THIS_MODULE, "driver_dev" ); if (IS_ERR(globalmem_devp->dev_class)) { printk("class create error\r\n" ); ret = -EBUSY; goto fail_malloc; } devices = device_create(globalmem_devp->dev_class, NULL , MKDEV(globalmem_major, 0 ), NULL , "globalmem" ); if (NULL == devices){ printk("device_create error\r\n" ); ret = -EBUSY; class_destroy(globalmem_devp->dev_class); goto fail_malloc; } ...
安装之后, 可以在/sys/class和/dev下找到driver_dev和globalmem
更多 这篇知识比较零碎。具体的测试代码在Gitee仓库中git@gitee.com :fishmwei/blog_code.git。
行动,才不会被动!
欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。
博客地址: https://fishmwei.github.io
掘金主页: https://juejin.cn/user/2084329776486919