有没有文件名的类似shm_open()的东西吗?

时间:2019-04-16 09:23:24

标签: unix posix shared-memory

POSIX shm_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()

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

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

4 个答案:

答案 0 :(得分:2)

不,没有。由于用于IPC的System V共享内存模型和POSIX共享文件映射都需要对文件进行操作,因此始终需要文件才能进行映射。

  带有mmap()

MAP_ANON|MAP_SHARED很不错,但不是文件   描述符它给出一个指针。指针无法在   exec边界,无法通过Unix域发送到另一个进程   套接字就像文件描述符一样。

正如John Bollinger所说,

  

既不是通过mmap()创建的内存映射,也不是POSIX共享内存   通过shm_open()或System V共享内存段获取的段   通过shmat()获得的信息将保存在exec中。

内存上必须有一个众所周知的地方,可以开会和交换信息。这就是为什么需要文件的原因。这样,exec之后,孩子就可以重新连接到适当的共享内存。

答案 1 :(得分:1)

  

这种tempfilename的使用很难携带且可靠。文件名的解释(名称空间是什么,权限的处理方式)在系统之间有所不同。

您可以mkstemp/dev/shm//tmp中创建唯一的文件名,然后为您打开文件。然后,您可以unlink的文件名,从而使其他进程无法打开该文件,除了具有从mkstemp返回的文件描述符的进程。

  

mkstemp():符合4.3BSD,POSIX.1-2001。

答案 2 :(得分:1)

解决问题的库

我设法编写了提供简单界面的a library

int shm_open_anon(void);

该库在没有警告的情况下编译,并在Linux,Solaris,MacOS,FreeBSD,OpenBSD,NetBSD,DragonFlyBSD和Haiku上成功运行了测试程序。您可能可以使其适应其他操作系统。请发送拉取请求。

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

库中使用的实现技术

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

有一些不可移植的东西,它们或多或少地等同于shm_open(),而没有文件名:

  • 从2008年开始,FreeBSD可以将SHM_ANON作为shm_open()的路径名。

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

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

  • 从5.4版开始,OpenBSD进行了shm_mkstemp()调用。您仍然必须shm_unlink()临时文件,但至少可以轻松安全地创建它。

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

  1. 为POSIX shm_open() name 参数找出与操作系统有关的格式。请注意,您无法通过的名称绝对是可移植的。例如,NetBSD和DragonFlyBSD对名称中的斜杠有冲突的要求。即使您的目标是使用命名的shm对象(为POSIX API设计的)而不是匿名对象(如我们在此所做的工作),这也适用。

  2. 在名称后添加一些随机字母和数字(通过读取/dev/random)。这基本上是mktemp()的工作,除了我们不检查文件系统中是否存在随机名。 name 参数的解释千差万别,因此没有合理的方法可移植地将其映射到实际文件名。而且Solaris并不总是提供mktemp()。出于所有实际目的,我们所采用的随机性将确保我们在需要时使用一秒钟的唯一名称。

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

  4. 立即调用shm_unlink()摆脱随机名称。文件描述符保留供我们使用。

POSIX不能隔离这种技术,但是:

  1. POSIX未指定shm_open() name 参数,因此也不能保证其他任何功能。
  2. 让上面的兼容性列表说明一切。

享受。

答案 3 :(得分:0)

为什么不创建访问权限为0的文件? 因此,没有进程能够“打开”它并让您在紧接其后安全地取消链接吗?