POSIX shared memory objects are normally file-backed, as a file in the file-system is used as a named data object for disparate processes to map into their individual address spaces for sharing. Non-file backed anonymous mappings can be shared between processes after a fork().
#include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #include <fcntl.h> /* For O_* constants */
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
int shm_open(const char *name, int oflag, mode_t mode);
Link with -lrt
-lrt
int shm_unlink(const char *name);
shm_open() is virtually identical in function to the normal open() system call except that the file created will be created in the RAM drive /dev/shm (a virtual file-system where files created within it exist entirely in memory and are not stored on any disk,) which can then be used as a file backing for a mmap'ed memory segment to be mapped into one or more processes address space. If the files permissions are set to allow another process to access the file, then the same file can be shm_opened by another process and mmap'ed into its address space, creating a shared memory segment between the two or more processes. shm_unlink() is used to delete the file created by shm_open(), which should be done sometime after the last process that will map the file has access to it.
shm_open()
open()
/dev/shm
shm_unlink()
#include <unistd.h> #include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
int ftruncate(int fd, off_t length);
The ftruncate() function can be used to size a file (by its file-descriptor) to a desired size. To increase or decrease the size of a file-backed mmap'ed memory region, you must increase or decrease the size of the file (this should be done before the mapping.) You can obviously also do this by writing data to the file.
ftruncate()
On success 0 is returned, -1 on failure and errno is set.
int sfd = shm_open("foo", O_RDWR | O_CREAT | O_TRUNC, 0666); if (sfd < 0) { perror("shm_open"); } // Make the file 4096 bytes in size: if (ftruncate(sfd, 4096) < 0) { perror("ftruncate"); } //... shm_unlink("foo");
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
The mmap() system call creates a mapping in the processes memory of length number of bytes starting at the optionally given address addr (use NULL to let the kernel decide where to place the mapping.) If the memory region to be mapped is a file, then fd should be the file descriptor of the file with offset set to the offset within the file to begin the mapping at. If the mapping is to be anonymous then, fd should be set to -1 and offset to 0.
mmap()
length
addr
fd
offset
prot is the binary OR of one or more of the following memory access permissions:
prot
PROT_EXEC
PROT_READ
PROT_WRITE
PROT_NONE
flags is one of MAP_SHARED or MAP_PRIVATE for either a shared memory mapping or a copy-on-write private mapping (note that changes made using MAP_PRIVATE are not written back to any file.) Additional flags can be binary OR'ed the above, such as MAP_ANONYMOUS which allows creating a non-file backed anonymous mapping.
flags
MAP_SHARED
MAP_PRIVATE
MAP_ANONYMOUS
The return value for mmap is the address of the memory region on success or MAP_FAILED ( (void *)-1 ) on failure.
(void *)-1
// Would map the file opened by shm_open() above: void *ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, sfd, 0);
int munmap(void *addr, size_t length);
munmap removes part of all of a mapped region. addr must be a multiple of the page size, however length does not need to be. Closing the file that is the file-backing for a memory region does not unmap the memory region.
munmap
munmap(ptr, 4096);
#include <stdio.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <string.h> #define SHM_FILE "shm-file" #define K 1024 struct message { int clr2send; char mbuf[K]; }; /** * Compile with: gcc -o writer writer.c -lrt */ int main(void) { char mesg[K]; struct message *m; int sfd = shm_open(SHM_FILE, O_RDWR | O_CREAT | O_TRUNC, 0666); if (sfd < 0) { perror("shm_open"); return 1; } if (ftruncate(sfd, sizeof(struct message)) < 0) { perror("ftruncate"); close(sfd); shm_unlink(SHM_FILE); return 1; } m = mmap(NULL, sizeof(struct message), PROT_READ | PROT_WRITE, MAP_SHARED, sfd, 0); if (m == MAP_FAILED) { perror("mmap"); close(sfd); shm_unlink(SHM_FILE); return 1; } m->clr2send = 0; while (1) { printf("? "); if (fgets(mesg, K, stdin) == NULL) break; while (m->clr2send == 0) usleep(100000); strncpy(m->mbuf, mesg, K); m->clr2send = 0; } close(sfd); shm_unlink(SHM_FILE); return 0; }
#include <stdio.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <string.h> #define SHM_FILE "shm-file" #define K 1024 struct message { int clr2send; char mbuf[K]; }; /** * Compile with: gcc -o reader reader.c -lrt */ int main(void) { char mesg[K]; struct message *m; int sfd = shm_open(SHM_FILE, O_RDWR, 0666); if (sfd < 0) { perror("shm_open"); return 1; } m = mmap(NULL, sizeof(struct message), PROT_READ | PROT_WRITE, MAP_SHARED, sfd, 0); if (m == MAP_FAILED) { perror("mmap"); close(sfd); shm_unlink(SHM_FILE); return 1; } while (1) { m->clr2send++; while (m->clr2send > 0) usleep(100000); printf("%s", m->mbuf); } close(sfd); return 0; }