This library provides a single C function:
int shm_open_anon(void);
It returns a file descriptor pointing to a shared memory region. On
failure, -1 is returned and errno is set.
The region is not bound to any pathname — it is anonymous like the
ones you get from mmap(). But whereas mmap() gives you a pointer,
this one gives you a file descriptor, which means you can pass it to
other processes even if they are not direct forks of the process that
made it.
On arrival, the descriptor has the close-on-exec flag set so it
doesn’t survive an exec() boundary. But you can call fcntl() to
unset the FD_CLOEXEC flag to make it survive. Then you can freely
pass it to subprocesses that start other executables. Make sure to
place it at a known file descriptor number (usually number 3 and up)
using dup2() so the other executable can find it.
You can also use sendmsg() with SCM_RIGHTS to send a copy of the
file descriptor to another process over a Unix domain socket. That
part of the BSD socket API is even more perplexing than the rest of
it, so there’s a convenience wrapper libancillary that offers "fd
passing for humans".
The region’s initial size is zero bytes. You need to use ftruncate()
to grow it, and then you’ll probably want to use mmap() to get a
pointer to actually access the memory. mmap() needs to know the size
of the region. If you pass the file descriptor to an unrelated
process, that process can use fstat() and then look at st_size in
the result.
Because the file descriptor is not bound to any file system or shared memory pathname, you don’t need to worry about a memory leak in case your processes terminate abruptly. There’s no need to do special cleanup — the operating system removes the shared memory object when all file descriptors accessing it are closed.
This technique is available in Linux kernel version 3.17 and later.
-
Use
memfd_create()— problem solved. -
memfd_create()is a system call that exists since kernel version 3.17. -
Even if the syscall is in your kernel, your libc does not necessarily have a C function (syscall wrapper) for it. GNU libc took years to add a wrapper.
-
You can get around that by calling the generic syscall wrapper
syscall(__NR_memfd_create, …)instead. Remember to typecast the arguments. -
__NR_memfd_createis the Linux syscall number (a small integer). Note that syscall numbers may differ by computer architecture. Use#include <linux/unistd.h>to get the right numbers for your architecture. -
Since
__NR_memfd_createis a preprocessor definition, you can use#ifdef __NR_memfd_createto check whether your Linux headers define it. -
If the syscall is not implemented in the kernel you are running, you get an errno value of
ENOSYSorENOTSUP(not sure which one).
This technique is not included in the current library since all
currently maintained Linux kernel versions implement the newer and
more robust memfd API, but it is still useful where compatibility
with older systems is needed.
-
In kernel versions before 3.17, a memory-backed file system was mounted into
/dev/shmor/run/shmdepending on the distro. (In fact, distros still mount such a file system, but it’s a bit less useful now.) -
You can use perfectly ordinary
open()andunlink()to operate on any files there. -
The safest and easiest way create a tempfile there is
mkostemp(). It’s in fact easier to use this than to useshm_open(). -
To force a file to be opened as a memory-backed tempfile instead of a disk file, regardless of which file system its pathname points to, you can give
O_TMPFILEtoopen()since kernel version 3.11. You really should useO_RDWRalong with it. Note also thatO_TMPFILEmay not be defined by library headers, but that constant is probably architecture independent so you may be able to get away with defining it yourself. -
https://lwn.net/Articles/619146/ (how
O_TMPFILEcame about)
-
Use
shm_open(SHM_ANON, O_RDWR, 0)— problem solved. -
The constant
SHM_ANONis defined to be1which is an unaligned pointer one byte away from the null pointer0. -
You must use the
O_RDWRflag. If you do not, the default isO_RDONLY(value zero) and that’s not allowed for shm objects. -
Permission bits can be zero, at least when subprocesses have the same user ID as the parent process that created the fd.
-
shm_mkstemp()is the thing to use. You need toshm_unlink()the path afterwards. -
Pathnames given to
shm_open()get translated into/tmp/<hash>.shmwhere<hash>is the SHA-256 hash of the pathname you gave. It doesn’t matter what slashes, if any, your pathname has. -
shm_mkstemp()callsshm_open()withO_RDWR | O_EXCL | O_CREATin a loop until it succeeds. Your pathname template gets the X’s filled in as withmktemp()and thenshm_open()applies its translation rules to that. So it doesn’t much matter what pathname you give. -
shm_unlink()translates path to shm path and doesunlink(). -
https://github.com/openbsd/src/blob/master/lib/libc/gen/shm_open.c
-
shm_open()is the best we can do. You need toshm_unlink()the path afterwards. -
The pathname given to
shm_open()must start with a slash. It must not have any other slashes. -
If the pathname does not start with a slash, or has other slashes, you get
EINVAL. -
Each pathname
/foois translated into/var/shm/.shmobj_foo. -
/var/shmis mounted as a tmpfs filesystem. The shm routines check this and if is’t not, you getENOTSUP. -
shm_open()translates your path to an shm path and then doesopen()withO_CLOEXEC | O_NOFOLLOW. -
shm_unlink()translates your path to an shm path and then doesunlink().
-
shm_open()is the best we can do. You need toshm_unlink()the path afterwards. -
shm_open()doesopen()but also usesfcntl()to set the undocumentedFPOSIXSHMflag. It also setsFD_CLOEXEC. -
shm_unlink()doesunlink(). -
Before 5.6.0 there was no pathname translation at all. Starting with 5.6.0 a tmpfs file system is mounted at
/var/run/shmduring boot, and shm pathnames are taken relative to that directory (with any number of leading slashes removed from the user-supplied pathname). -
To generate the pathname, I couldn’t come up with anything better than generating a random filename of the form
/shm-XXXXXXX. -
https://leaf.dragonflybsd.org/cgi/web-man?command=shm_open§ion=3
-
https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/lib/libc/gen/posixshm.c
-
I didn’t find anything better than
shm_open()andshm_unlink()with POSIX semantics. -
Pathnames given to
shm_open()get translated into either/tmp/.SHMD<path>or/tmp/.<hash>/.SHMD/<path>where<hash>is the MD5 hash of the pathname you gave. There are also equivalent.SHMLlock files. -
https://docs.oracle.com/cd/E26505_01/html/816-5171/shm-open-3rt.html
-
https://docs.oracle.com/cd/E26505_01/html/816-5171/shm-unlink-3rt.html
-
https://github.com/kofemann/opensolaris/blob/master/usr/src/lib/libc/port/rt/shm.c
-
https://github.com/kofemann/opensolaris/blob/master/usr/src/lib/libc/port/rt/pos4obj.c
-
I didn’t find anything better than
shm_open()andshm_unlink(). -
Translates your pathname so it goes under the
/var/shared_memorydirectory. Removes any number of leading slashes, then escapes/by%sand%by%%(these are literal percent signs, not format string magic). -
Othersise
shm_open()andshm_unlink()are justopen()andunlink().shm_open()opens withFD_CLOEXEC. -
Not sure whether or not the original BeOS had these same semantics.
-
https://github.com/haiku/haiku/blob/master/src/system/libroot/posix/sys/mman.cpp
-
Probably have to use
shm_open()andshm_unlink(). -
Not sure if clearing the close-on-exec flag and using
dup2()will have the desired effect. -
Translates your pathname by removing at most one slash from the beginning. Then puts that name under
/dev/shm/with no escaping of slashes. So it’s best to use a name that has only one slash with the start; if you use more slashes, those subdirectories may have to exist under/dev/shm. -
As far as I can tell,
/dev/shmis an ordinary directory on a disk-backed file system, not a special memory-back file system. So expect shared memory to be slow, especially on traditional hard disks. -
Cygwin also supports System V IPC (
shmget()et.al.) and it seems to be specially implemented bycygserveron a better foundation. -
https://github.com/Alexpux/Cygwin/blob/master/newlib/libc/sys/linux/shm_open.c
-
http://pipeline.lbl.gov/code/3rd_party/licenses.win/Cygwin/cygserver.README
Chris Wellons wrote a thoughtful blog post
(Mapping Multiple Memory
Views in User Space, 2016-04-10) detailing how to use shm_open()
without a filename. It also covers Windows API equivalents to
shm_open() and mmap(), which are CreateFileMapping() and
MapViewOfFile().
Ludovic P improved Linux portability and helped design the random
filename generator for shm_open().
Maxim Egorushkin suggested using plain mkostemp("/dev/shm/…" ,…)
instead of shm_open() on Linux.