13

mmap() can be optionally supplied with a fixed location to place the map. I would like to mmap a file and then have it available to a few different programs at the same virtual address in each program. I don't care what the address is, just as long as they all use the same address. If need be, the address can be chosen by one of them at run time (and communicated with the others via some other means).

Is there an area of memory that Linux guarantees to be unused (by the application and by the kernel) that I can map to? How can I find one address that is available in several running applications?

SoapBox
  • 20,457
  • 3
  • 51
  • 87

3 Answers3

7

Not really, no. With address space randomisation on modern linux systems it is very hard to guarantee anything about what addresses may or may not be used.

Also, if you're thinking of using MAP_FIXED then be aware that you need to be very careful as it will cause mmap to unmap anything that may already be mapped at that address which is generally a very bad thing.

I really think you will need to find another solution to your problem...

TomH
  • 8,900
  • 2
  • 32
  • 30
  • +1 True, it is much better to think in terms of "offset from base address" for storing shared data, this makes fixed absolute addresses superfluous. – Damon Jun 22 '11 at 20:38
  • @Damon for a large and varied datasets not originally designed to be shared changing those offsets back into real addresses can be very difficult. – SoapBox Jun 22 '11 at 20:40
  • 16
    An aside: `MAP_FIXED` **can be used safely** if you first make a single mapping without `MAP_FIXED`, then use `MAP_FIXED` to create various mappings at fixed addresses relative to one another over top of the original throw-away mapping that was at a kernel-assigned location. With a sufficiently large mapping size, this might solve OP's problem. – R.. GitHub STOP HELPING ICE Jun 23 '11 at 05:24
  • I don't think this answer is conclusive. If you write and run a simple program which prints the return address of a `mmap` call (which does not specify the address), we can see that although the addresses are randomized each run, the range of the randomization is extremely constrained (at least when compared to the size of the 64-bit address space). I strongly suspect that the kernel can provide some guarantees of some address ranges that will always be available, but haven't found any documentation for this yet. – Vladimir Panteleev Mar 06 '22 at 01:05
  • Note that MAP_FIXED_NOREPLACE allows you to avoid accidentally unmapping something your application is already using it. – Bruce Adams May 21 '22 at 13:47
  • If you're debugging a memory corruption bug and you need to have your mappings consistent across your debugging sessions, this is exactly what you need. – Amir Feb 07 '23 at 15:56
5

Two processes can map a shared memory block to the same virtual address using shm_open() and mmap(); that is, the virtual address returned from mmap() can be the same for both processes. I found that Linux will by default give different virtual addresses to different processes for the same piece of shared memory, but that using mmap() with MAP_FIXED will force Linux to supply the same virtual address to multiple processes.

The process that creates the shared memory block must store the virtual address somewhere, either within the shared memory, in a file, or with some other method so that another process can determine the original virtual address. The known virtual address is then used in the mmap() call, along with the MAP_FIXED flag.

I was able to use the shared memory to do this. When doing so, the "golden" virtual address is stored within the shared memory block; I made a structure that contains a number of items, the address being one of them, and initialized it at the beginning of the block.

A process that wants to map that shared memory must execute the mmap() function twice; once to get the "golden" virtual address, then to map the block to that address using the MAP_FIXED flag.

Interestingly, I'm working with an embedded system running a 2.6 kernel. It will, by default, supply the same virtual address to all mmap() calls to a given file descriptor. Go figure.

Bob Wirka

bobwirka
  • 324
  • 1
  • 6
  • 10
  • I'm also annoyed by the fact that `mmap` gives different addresses for the same piece of shared memory. In an attempt to work around this, I tried to use `MAP_FIXED`. But it does not work... How did you make it work? Please add example code to your answer. Also see https://stackoverflow.com/questions/50093733/ – Igor Liferenko May 01 '18 at 14:18
  • See also https://stackoverflow.com/questions/72194235/is-there-a-way-to-an-share-address-mapping-between-two-unrelated-processes-on-li?noredirect=1#comment127751665_72194235 . Does this only work with shm_open and not with open (i.e. backed by tmpfs but not a regular fs). – Bruce Adams May 20 '22 at 07:32
2

You could look into doing a shared memory object using shmget(), shmat(), etc. First have the process that obtains the right to initialize the shared memory object read in your file and copy it into the shared memory object address space. Now any other process that simply gets a return shared memory ID value can access the data in the shared memory space. So for instance, you could employ some type initialization scheme like the following:

#include <sys/shm.h>

#define KEYVALUE 1000 //arbitrary value ... just needs to be shared between your processes

int file_size
//read your file and obtain its size in bytes;

//try to create the shared memory object
int shared_mem_id;
void* shared_mem_ptr = NULL;

if ((shared_mem_id = shmget(KEYVALUE, file_size, S_IRUSR | S_IWUSR IPC_CREAT | IPC_EXCL)) == -1)
{
    if (errno == EEXIST)
    {
        //shared memory segment was already created, so just get its ID value
        shared_mem_id = shmget(KEYVALUE, file_size, S_IRUSR | S_IWUSR);
        shared_mem_ptr = shmat(shared_mem_id, NULL, 0)
    }
    else
    {
        perror("Unable to create shared memory object");
        exit(1);
    }
}
else
{
    shared_mem_ptr = shmat(shared_mem_id, NULL, 0);

    //copy your file into shared memory via the shared_mem_ptr

}

//work with the shared data ...

The last process to use the shared memory object, will, just before destroying it, copy the modified contents from shared memory back into the actual file. You may also want to allocate a structure at the beginning of your shared memory object that can be used for synchronization, i.e., there would be some type of "magic number" that the initializing process will set so that your other processes will know that the data has been properly initialized in the shared memory object before accessing it. Alternatively you could use a named semaphore or System V semaphore to make sure that no process tries to access the shared memory object before it's been initialized.

Jason
  • 31,834
  • 7
  • 59
  • 78