dpdk学习之多进程simple_mp源代码分析

来源:互联网 发布:梦天堂软件 编辑:程序博客网 时间:2024/06/06 05:51

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 intlcore_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