1.实现思路分析
dpdk提供了进程间共享的方法,需要以下几步来完成。
1.rte_ring需要与rte_mempool配合使用,通过rte_mempool来共享内存。
// flags:标识是单消费者/生产者或者多消费者/生产者struct rte_ring *ring = rte_ring_create("message_ring",
ring_size, rte_socket_id(), flags);
struct rte_mempool *message_pool = rte_mempool_create(
"message_pool", pool_size,
string_size, pool_cache, 0,
NULL, NULL, NULL, NULL,
rte_socket_id(), flags);
2.首先primary进程创建ring和mempool,secondary进程在primary进程启动后,通过rte_ring_lookup和rte_mempool_lookup来获取ring和mempool的地址。
struct rte_ring *ring = rte_ring_lookup("message_ring");
struct rte_mempool *message_pool = rte_mempool_lookup(
"message_pool");
3.使用时,rte_mempool_get从mempool中获取一个对象,然后使用rte_ring_enqueue入队列,另一个进程通过rte_ring_dequeue来出队列,使用完成后需要rte_mempool_put将对象放回mempool。
2.一步步进行代码分析
main函数,将在primary进程创建两个ring队列
- 发送队列 PRI_2_SEC
- 接受队列 SEC_2_PRI
对于secondary进程,查找发送和接受队列,顺序跟primary相反:
- 发送队列 SEC_2_PRI
- 接受队列 PRI_2_SEC
当在primary进程执行send hello1时,使用的是dpdk自带的cmdline库
struct cmdline *cl = cmdline_stdin_new(simple_mp_ctx, "\nsimple_mp > ");
if (cl == NULL)
rte_exit(EXIT_FAILURE, "Cannot create cmdline instance\n");
cmdline_interact(cl);
cmdline_stdin_exit(cl);
定位到simple_mp_ctx结构体中
cmdline_parse_ctx_t simple_mp_ctx[] = {
(cmdline_parse_inst_t *)&cmd_send,
(cmdline_parse_inst_t *)&cmd_quit,
(cmdline_parse_inst_t *)&cmd_help,
NULL,
};
cmd_send对应”send”命令的结构体指针
cmd_quit对应”quit”命令的结构体指针
cmd_help对应”help”命令的结构体指针
点击进入cmd_send
cmdline_parse_inst_t cmd_send = {
.f = cmd_send_parsed, /* function to call */
.data = NULL, /* 2nd arg of func */
.help_str = "send a string to another process",
.tokens = { /* token list, NULL terminated */
(void *)&cmd_send_action,
(void *)&cmd_send_message,
NULL,
},
};
一切都清楚了,当在控制台输出send xxx命令时,会调用cmd_send_parsed函数进行逻辑处理
static void cmd_send_parsed(void *parsed_result,
__attribute__((unused)) struct cmdline *cl,
__attribute__((unused)) void *data)
{
void *msg = NULL;
struct cmd_send_result *res = parsed_result;
//从内存池中获取一个对象
if (rte_mempool_get(message_pool, &msg) < 0)
rte_panic("Failed to get message buffer\n");
snprintf((char *)msg, string_size, "%s", res->message);
//ring入队操作
if (rte_ring_enqueue(send_ring, msg) < 0) {
printf("Failed to send message - message discarded\n");
//将对象归还给内存池
rte_mempool_put(message_pool, msg);
}
}
对于primary进程,
/* call lcore_recv() on every slave lcore */
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
rte_eal_remote_launch(lcore_recv, NULL, lcore_id);
}
在每个slave核心上执行lcore_recv函数调用。lcore_recv函数代码如下:
static int
lcore_recv(__attribute__((unused)) void *arg)
{
unsigned lcore_id = rte_lcore_id();
printf("Starting core %u\n", lcore_id);
while (!quit){
void *msg;
//ring 出队操作
if (rte_ring_dequeue(recv_ring, &msg) < 0){
usleep(5);
continue;
}
printf("core %u: Received '%s'\n", lcore_id, (char *)msg);
//将之前从内存池中获取的对象归还到内存池
rte_mempool_put(message_pool, msg);
}
return 0;
}
3.
至此,我们总结下,进程之间通过ring来共享数据内容,数据内容是存储在从内存池申请的对象上的。
流程如下:
从内存池申请对象->入队ring->将对象归还给内存池
参考资料:
dpdk的使用说明,请参考
http://blog.csdn.net/njnu_mjn/article/details/52474300