Linux零拷贝:使用vmsplice在两个进程之间传输内存页面

nos*_*sid 20 c linux virtual-memory splice

目前,我试图了解splice/vmsplice的价值.关于IPC的用例,我在stackoverflow上偶然发现了以下答案:https://stackoverflow.com/a/1350550/1305501

问题:如何使用vmsplice将内存页面从一个进程转移到另一个进程而不复制数据(即零拷贝)?

上面提到的答案声称它是可能的.但是,它不包含任何源代码.如果我理解vmsplice正确的文档,如果内存被正确分配和对齐,以下函数将把内存页面转移到管道(内核缓冲区)而不复制.为了便于演示而省略了错误处理.

// data is aligned to page boundaries,
// and length is a multiple of the page size
void transfer_to_pipe(int pipe_out, char* data, size_t length)
{
    size_t offset = 0;
    while (offset < length) {
        struct iovec iov { data + offset, length - offset };
        offset += vmsplice(pipe_out, &iov, 1, SPLICE_F_GIFT);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是如何在不复制的情况下从用户空间访问内存页面?显然,以下方法不起作用:

  • vmsplice:此功能也可用于反向.但根据内核源代码中的注释,数据将被复制.
  • read:我可以想象,如果内存正确对齐,这个函数会产生一些魔力,但我对此表示怀疑.
  • mmap:管道不可能.但是有没有可以使用的某种虚拟文件,即splice虚拟文件的内存页面mmap呢?
  • ......?

根本不可能vmsplice吗?

小智 7

正如R ..所提到的,你只需要以某种方式将fd传递给接收进程,而另一方面将它用作普通的fd.

编辑: 实际上,你必须在发送端使用vmsplice()将缓冲区映射到管道,并在管道另一端的接收端上拼接().在这里查看示例.

另一种选择是使用共享mmap.

  • 让我们假设另一个进程已经有一个fd到管道的另一端.问题是:它可以将内存页面映射到其地址空间而无需复制数据吗?我怀疑`read(2)`是否包含这样的优化,是吗? (3认同)