首页 > 解决方案 > 有没有文件名的 shm_open() 之类的东西?

问题描述

POSIXshm_open()函数返回可用于访问共享内存的文件描述符。这非常方便,因为可以使用所有控制文件描述符的传统机制来控制共享内存。

唯一的缺点是shm_open()总是想要一个文件名。所以我需要这样做:

// Open with a clever temp file name and hope for the best.
fd = shm_open(tempfilename, O_RDWR | O_CREAT | O_EXCL, 0600);

// Immediately delete the temp file to keep the shm namespace clean.
shm_unlink(tempfilename);

// Then keep using fd -- the shm object remains as long as there are open fds.

这种使用tempfilename很难便携和可靠地进行。文件名的解释(命名空间是什么,如何处理权限)在系统之间有所不同。

在许多情况下,使用共享内存对象的进程不需要文件名,因为只需将文件描述符从一个进程传递给另一个进程,就可以更简单、更安全地访问该对象。那么有没有一些类似shm_open()但可以在不触及共享内存文件名命名空间的情况下使用的东西?

mmap()withMAP_ANON|MAP_SHARED很棒,但它提供了一个指针,而不是文件描述符。指针不能在 exec 边界上存活,也不能像文件描述符一样通过 Unix 域套接字发送到另一个进程。

默认情况下,返回的文件描述符shm_open()也不存在 exec 边界:POSIX 定义表示已设置与新文件描述符关联的 FD_CLOEXEC 文件描述符标志。但是可以fcntl()在 MacOS、Linux、FreeBSD、OpenBSD、NetBSD、DragonFlyBSD 和可能的其他操作系统上清除标志。

标签: unixposixshared-memory

解决方案


解决问题的图书馆

我设法编写了一个提供简单接口的库

int shm_open_anon(void);

该库在没有警告的情况下编译并成功在 Linux、Solaris、MacOS、FreeBSD、OpenBSD、NetBSD、DragonFlyBSD 和 Haiku 上运行测试程序。您也许可以将其适应其他操作系统;如果你这样做,请发送请求请求。

该库返回一个设置了 close-on-exec 标志的文件描述符。您可以fcntl()在所有受支持的操作系统上清除该标志,这将允许您将 fd 传递给exec(). 测试程序证明这是可行的。

库中使用的实现技术

该库的自述文件对每个操作系统已完成和未完成的内容进行了非常精确的注释。这是主要内容的摘要。

有几个不可移植的东西或多或少等同于shm_open()没有文件名:

  • FreeBSD 可以作为2008 年以来SHM_ANON的路径名。shm_open()

  • memfd_create()Linux从内核版本 3.17开始就有系统调用。

  • 早期版本的 Linux 可以使用mkostemp(name, O_CLOEXEC | O_TMPFILE)wherename类似/dev/shm/XXXXXX. 请注意,我们shm_open()在这里根本没有使用——mkostemp()隐含地使用了一个完全普通的open()调用。Linux 安装了一个特殊的内存支持文件系统,/dev/shm但一些发行版使用它/run/shm,所以这里有陷阱。而且您仍然必须 shm_unlink() 临时文件。

  • OpenBSDshm_mkstemp()自 5.4 版起就有一个电话。您仍然需要shm_unlink()临时文件,但至少它很容易安全地创建。

对于其他操作系统,我执行了以下操作:

  1. 找出POSIX的nameshm_open()参数的操作系统相关格式。请注意,没有可以传递的名称是绝对可移植的。例如,NetBSD 和 DragonFlyBSD 对名称中的斜线有冲突的要求。即使您的目标是使用命名的 shm 对象(为其设计 POSIX API)而不是匿名对象(正如我们在这里所做的那样),这也适用。

  2. 将一些随机字母和数字附加到名称(通过从 读取/dev/random)。这基本上就是mktemp()这样做的,除了我们不检查我们的随机名称是否存在于文件系统中。name参数的解释千差万别,因此没有合理的方法可以将其可移植地映射到实际文件名。此外 Solaris 并不总是提供mktemp(). 出于所有实际目的,我们输入的随机性将确保在我们需要的那几分之一秒内有一个唯一的名称。

  3. 通过 . 打开具有该名称的 shm 对象shm_open(name, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600)。在我们的随机文件名已经存在的天文机会中,O_EXCL无论如何都会导致此调用失败,因此不会造成任何伤害。在某些系统上,0600权限(所有者读写)是必需的,而不是空白0权限。

  4. 立即致电shm_unlink()以摆脱随机名称。文件描述符仍然供我们使用。

POSIX 不保证这种技术可以工作,但是:

  1. POSIX 未指定 name 参数,因此也不能保证其他任何方法都可以正常工作shm_open()
  2. 我会让上面的兼容性列表不言自明。

享受。


推荐阅读