orientnab
orientnab

Reputation: 68

How to map shared memory to the same address in different processes?

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

Answers (1)

Nate Eldredge
Nate Eldredge

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 of MAP_PRIVATE, MAP_SHARED or MAP_SHARED_VALIDATE.

Change it to MAP_SHARED | MAP_FIXED and it runs successfully for me.

Upvotes: 3

Related Questions