Intel の DPDK と連携する Rust プログラムを作成していますが、よくわからない問題に遭遇しました。現在、Rust プログラムで DPDK ライブラリの関数を実行できますが、C で記述された同じプログラムとは結果が異なります。
Rust プログラム出力 -
~/Dev/rust_eal_init_test$ sudo target/debug/rust_eal_init_test
EAL: Detected 8 lcore(s)
EAL: No free hugepages reported in hugepages-2048kB
EAL: Probing VFIO support...
~/Dev/rust_eal_init_test$
Cプログラム出力 -
~/Dev/c_eal_init_test$ sudo build/c_eal_init_test
EAL: Detected 8 lcore(s)
EAL: No free hugepages reported in hugepages-2048kB
EAL: Probing VFIO support...
PMD: bnxt_rte_pmd_init() called for (null)
EAL: PCI device 0000:00:19.0 on NUMA socket -1
EAL: probe driver: 8086:153a rte_em_pmd
EAL: PCI device 0000:04:00.0 on NUMA socket -1
EAL: probe driver: 8086:1533 rte_igb_pmd
~/Dev/c_eal_init_test$
DPDK は、Rust でリンクしている静的ライブラリとしてコンパイルされています。以下は、Rust と C プログラムの両方のコードです。
さびた main.rs -
extern crate libc;
use std::env;
use std::process::exit;
use std::ffi::CString;
use libc::{c_int, c_char,};
extern {
pub fn rte_eal_init(argc: c_int, argv: *mut *mut c_char) -> c_int;
}
// librte_eal
pub fn dpdk_rte_eal_init(argc: i32, argv: Vec<String>) -> i32 {
let mut args: Vec<*mut c_char> = argv.iter().map(|x| CString::new(x.clone()).unwrap().into_raw()).collect();
let retc: c_int = unsafe { rte_eal_init(argc as c_int, args.as_mut_ptr()) };
let ret: i32 = retc as i32;
ret
}
fn main() {
let args: Vec<String> = env::args().collect();
let ret: i32 = dpdk_rte_eal_init(args.len() as i32, args);
if ret < 0 {
exit(ret);
}
}
C main.c -
#include <stdio.h>
#include <string.h>
#include <rte_eal.h>
#include <rte_debug.h>
int
main(int argc, char **argv)
{
int ret;
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_panic("Cannot init EAL\n");
return 0;
}
DPDK のソースを調べ、print ステートメントを追加して、どこが違うのかを調べました。このrte_eal_init()
関数はeal.cにあり、他のさまざまな init 関数を呼び出します。rte_eal_dev_init()
余分な出力のトリガーは、eal_common_dev.cで呼び出される別の関数からのものです。
rte_eal_dev_init()
-
int
rte_eal_dev_init(void)
{
struct rte_devargs *devargs;
struct rte_driver *driver;
/*
* Note that the dev_driver_list is populated here
* from calls made to rte_eal_driver_register from constructor functions
* embedded into PMD modules via the PMD_REGISTER_DRIVER macro
*/
/* call the init function for each virtual device */
TAILQ_FOREACH(devargs, &devargs_list, next) {
if (devargs->type != RTE_DEVTYPE_VIRTUAL)
continue;
if (rte_eal_vdev_init(devargs->virt.drv_name,
devargs->args)) {
RTE_LOG(ERR, EAL, "failed to initialize %s device\n",
devargs->virt.drv_name);
return -1;
}
}
/* Once the vdevs are initalized, start calling all the pdev drivers */
TAILQ_FOREACH(driver, &dev_driver_list, next) {
if (driver->type != PMD_PDEV)
continue;
/* PDEV drivers don't get passed any parameters */
driver->init(NULL, NULL);
}
return 0;
}
Rust プログラムは関数に入りますが、マクロrte_eal_dev_init()
のループに入ることはありません。TAILQ_FOREACH()
このように、マクロのすぐ上と下に print ステートメントを追加するとしたら、
printf("Test before TAILQ_FOREACH\n");
TAILQ_FOREACH(driver, &dev_driver_list, next) {
printf("Test in TAILQ_FOREACH\n");
if (driver->type != PMD_PDEV)
continue;
/* PDEV drivers don't get passed any parameters */
driver->init(NULL, NULL);
}
これにより、Rustで次の出力が得られます-
~/Dev/rust_eal_init_test$ sudo target/debug/rust_eal_init_test
EAL: Detected 8 lcore(s)
EAL: No free hugepages reported in hugepages-2048kB
EAL: Probing VFIO support...
Test before TAILQ_FOREACH
~/Dev/rust_eal_init_test$
そして、Cでの次の出力 -
~/Dev/c_eal_init_test$ sudo build/c_eal_init_test
EAL: Detected 8 lcore(s)
EAL: No free hugepages reported in hugepages-2048kB
EAL: Probing VFIO support...
Test before TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
PMD: bnxt_rte_pmd_init() called for (null)
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
Test in TAILQ_FOREACH
EAL: PCI device 0000:00:19.0 on NUMA socket -1
EAL: probe driver: 8086:153a rte_em_pmd
EAL: PCI device 0000:04:00.0 on NUMA socket -1
EAL: probe driver: 8086:1533 rte_igb_pmd
~/Dev/c_eal_init_test$
sys/queue.hTAILQ_FOREACH()
で定義されていることがわかりました。私が理解しているように、静的ライブラリにリンクしても、ライブラリが他の何かに動的にリンクしているという問題は発生しません。これは正しいです?