Tony
Tony

Reputation: 3638

Share process memory with mmap

I have a C program that generates large amounts of data in memory, and I need to share one particular section of this data in memory, so that another process can have read access to it.

I'm attempting to use mmap to do this, but I'm not having much success. Here is my code:

//Code above generates a pointer to the memory section I need to share, named addr

if (infoBlock->memory_size == 1073741824) { //This is the data block I need to share
   int err, fd;
   fd = open("/tmp/testOutput", (0_RDWR | 0_CREAT), S_IWUSR);
   if (fd < 0) {
         perror("Couldn't create output file\n");
         goto failedExit;
    }

    unsigned *p = mmap(addr, 1073741824, PROT_READ, (MAP_SHARED | MAP_FIXED), fd, 0);
    if (!p) {perror("mmap failed"); goto failedExit; }
    printf("p is now: %p\n", p); //This should point to the shared mapping
    printf("%u\n", *p); //Try to print out some data from the mapping

}

After running the program, I can see the file /tmp/testOutput is there, but it's size is 0. I'm not sure if that's a normal thing with memory mappings, as it's not technically a file. Also all of the output within my program points to the same memory address.

I can also see the memory map present within the /proc/PID/maps, with a reference to /tmp/testOutput.

Everything seems to run, however when it comes to dereferencing the pointer, the program exits, I'm assuming this is because I've done the mapping wrong, and the pointer is pointing to something it shouldn't be.

If anyone can spot what I'm doing wrong, or can offer some advice, it would be greatly appreciated.

Thanks!

Upvotes: 0

Views: 2450

Answers (2)

Useless
Useless

Reputation: 67713

You've mapped the storage associated with that file (or tried to) into your process, and you've insisted that it be mapped at an address you're already using for something else (presumably, addr was allocated somehow).

You don't say whether p actually does have the address you requested, and as suspectus points out, your error checking is broken.

Your Confusion:

You can't associate arbitrary heap or other process memory pages with a file after the fact. You have to allocate them in the filesystem, and then map them. (There is a way to associate them with a UNIX pipe using vmsplice, although it isn't exactly what you asked for).

Note the MMAP_FIXED flag will just replace the page which was occupied by your data, with the new pages associated with the file. Without that flag, the address hint would be ignored and the mapping placed elsewhere.

The Solution:

  1. ftruncate the file to your desired size before mapping it (this allocates storage in the filesystem)
  2. map it and then populate it
  3. fix your mmap error checking

If you can't change your allocation scheme, the best you can manage is to copy your process-local memory into the mapping, in which case you might as well just write it to the file.

The ideal case would look something like this:

void *alloc_mmap(const char *filename, size_t length)
{
    int fd;
    fd = open(filename, (0_RDWR | 0_CREAT), S_IWUSR);
    if (fd < 0) {
        perror("Couldn't create output file\n");
        return NULL;
    }
    if (ftruncate(fd, length)) {
        perror("Couldn't grow output file\n");
        close(fd);
        return NULL;
    }

    void *p = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0);
    if (p == -1) {
        perror("mmap failed");
        close(fd);
        return NULL;
    }
    close(fd);
    return p;
}

// now you've allocated your memory, you can populate it and it will be
// reflected in the file

Upvotes: 5

suspectus
suspectus

Reputation: 17258

Here is an extract from the mmap man page.

   On  success,  mmap() returns a pointer to the mapped area.  On error, the value
   MAP_FAILED (that is, (void *) -1) is returned, and errno is set  appropriately.
   On  success,  munmap()  returns 0, on failure -1, and errno is set (probably to
   EINVAL).

The test for success should be changed to test for -1 return value of mmap. Then check the errno value. HTH.

Upvotes: 1

Related Questions