Reputation: 68
I'm trying to share some data between different processes but I would like to use the same address in all of them.
From what I've read, it seems that this should be possible using mmap()
with the MAP_FIXED
flag (or MAP_FIXED_NOREPLACE
).
Some people suggest to create a shared block and then broadcast the address of that memory block to all the other processes. This comment is a good summary of the whole idea.
So I tried to implement that into this example. There are a sender and a receiver. The sender will create a shared block of memory. The receiver tries to allocate that block of memory at the same address. The address is passed around using a shared memory block too.
The issue is that the receiver can't map the memory object to said address. I get EINVAL error.
Is it possible to do what I'm trying? If so, how or what am I doing wrong in this example?
// header.h
#pragma once
#define SHM_DATA_ADDR "/bitarray-addr"
#define SHM_DATA "/bitarray-data"
#define NUM 3
#define SIZE (NUM * sizeof(int))
#define SIZE_ADDR (sizeof(void *))
// sender.c
#include "header.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stddef.h>
int main() {
// Open the shared memory object for read-only access
// Set permissions
int fd = shm_open(SHM_DATA, O_CREAT | O_EXCL | O_RDWR, 0600);
int fd_addr = shm_open(SHM_DATA_ADDR, O_CREAT | O_EXCL | O_RDWR, 0600);
ftruncate(fd, SIZE);
ftruncate(fd_addr, SIZE_ADDR);
// Establish mapping between address space and memory object
int RDWR = PROT_READ | PROT_WRITE;
int *data = (int *)mmap(0, SIZE, RDWR, MAP_SHARED, fd, 0);
void **data_addr = (void **)mmap(0, SIZE_ADDR, RDWR, MAP_SHARED, fd_addr, 0);
*data_addr = data;
printf("%p\n", data);
printf("%p\n", data_addr);
printf("%p\n", *data_addr);
// Unmap address space
munmap(data_addr, SIZE);
munmap(data, SIZE);
// Close file descriptors
close(fd_addr);
close(fd);
return EXIT_SUCCESS;
}
// receiver.c
#include "header.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stddef.h>
#include <errno.h>
int main() {
// Open the shared memory object for read-only access
// Set permissions
int fd = shm_open(SHM_DATA, O_RDONLY, 0600);
int fd_addr = shm_open(SHM_DATA_ADDR, O_RDONLY, 0600);
ftruncate(fd, SIZE);
ftruncate(fd_addr, SIZE_ADDR);
// Establish mapping between address space and memory object
void **data_addr = (void **)mmap(0, SIZE_ADDR, PROT_READ, MAP_SHARED, fd_addr, 0);
int *data = (int *)mmap(*data_addr, SIZE, PROT_READ, MAP_FIXED, fd, 0);
printf("%p\n", data_addr);
printf("%p\n", *data_addr);
printf("%p\n", data);
// Unmap address space
munmap(data_addr, SIZE_ADDR);
munmap(data, SIZE);
// Close file descriptors
close(fd_addr);
close(fd);
// Destroy shared memory object
shm_unlink(SHM_DATA_ADDR);
shm_unlink(SHM_DATA);
return EXIT_SUCCESS;
}
Upvotes: 2
Views: 3300
Reputation: 57922
From the mmap(2)
man page, emphasis mine:
The flags argument determines whether updates to the mapping are visible to other processes mapping the same region, and whether updates are carried through to the underlying file. This behavior is determined by including exactly one of the following values in flags: [
MAP_SHARED
,MAP_SHARED_VALIDATE
,MAP_PRIVATE
]In addition, zero or more of the following values can be ORed in flags: [
MAP_ANONYMOUS
,MAP_FIXED
, etc]
In your receiver code, you have:
int *data = (int *)mmap(*data_addr, SIZE, PROT_READ, MAP_FIXED, fd, 0);
which does not include any of MAP_SHARED
, MAP_SHARED_VALIDATE
, MAP_PRIVATE
, hence the error. It's even stated explicitly in the Errors section:
EINVAL
:flags
contained none ofMAP_PRIVATE
,MAP_SHARED
orMAP_SHARED_VALIDATE
.
Change it to MAP_SHARED | MAP_FIXED
and it runs successfully for me.
Upvotes: 3