Mapped Memory

Mapped memory permits different processes to communicate via a shared file. To map an ordinary file to a process’s memory, use the mmap (“Memory MAPped,” pronounced “em-map”) call. The first argument is the address at which you would like Linux to map the file into your process’s address space; the value NULL allows Linux to choose an available start address. The second argument is the length of the map in bytes. The third argument specifies the protection on the mapped address range. The protection consists of a bitwise “or” of PROT_READPROT_WRITE, and PROT_EXEC, corresponding to read, write, and execution permission, respectively. The fourth argument is a flag value that specifies additional options. The fifth argument is a file descriptor opened to the file to be mapped. The last argument is the offset from the beginning of the file from which to start the map. You can map all or part of the file into memory by choosing the starting offset and length appropriately.

The flag value is a bitwise “or” of these constraints:

  • MAP_FIXED— If you specify this flag, Linux uses the address you request to map the file rather than treating it as a hint. This address must be page-aligned.
  • MAP_PRIVATE— Writes to the memory range should not be written back to the attached file, but to a private copy of the file. No other process sees these writes. This mode may not be used with MAP_SHARED.
  • MAP_SHARED— Writes are immediately reflected in the underlying file rather than buffering writes. Use this mode when using mapped memory for IPC. This mode may not be used with MAP_PRIVATE.

If the call succeeds, it returns a pointer to the beginning of the memory. On failure, it returns MAP_FAILED.

When you’re finished with a memory mapping, release it by using munmap. Pass it the start address and length of the mapped memory region. Linux automatically unmaps mapped regions when a process terminates.

Let’s look at two programs to illustrate using memory-mapped regions to read and write to files. Here is a code that writes  a Random Number to a Memory-Mapped File, then reads it.

/**
  Memeory-Mapped File Example : mmap-rw.c
**/

#include
#include
#include
#include <sys/mman.h>
#include <sys/stat.h>
#include
#include
#define FILE_LENGTH 0x100

/* Return a uniformly random number in the range [low,high]. */
int random_range (unsigned const low, unsigned const high)
{
 unsigned const range = high - low + 1;
 return low + (int) (((double) range) * rand () / (RAND_MAX + 1.0));
}

int main (int argc, char* const argv[])
{
  int fd;
  void* file_memory;
  int integer;
/* Seed the random number generator. */
  srand (time (NULL));

/* Prepare a file large enough to hold an unsigned integer. */
  fd = open (argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
  lzeek (fd, FILE_LENGTH+1, SEEK_SET);
  write (fd, "", 1);
  lzeek (fd, 0, SEEK_SET);

/* Create the memory mapping. */
  file_memory = mmap (0, FILE_LENGTH, PROT_READ | PROT_WRITE,
                      MAP_PRIVATE, fd, 0);
  close (fd);

  integer = random_range(100, 200);

/* Write a random integer to memory-mapped area. */
  sprintf((char*) file_memory, "%d\n", integer);
  printf("written : %d\n", integer);

/* Read the integer, print it out, and double it.  */
  sscanf (file_memory, "%d", &integer);
  printf ("read: %d\n", integer);

  /* Release the memory (unnecessary because the program exits). */
  munmap (file_memory, FILE_LENGTH);

  return 0;
}

Change the lzeek to lseek in the code (my hosting does not allow me to use lseek functions). Compile with gcc and run it as follows.

$> gcc mmap-rw.c -o mmap-rw.o

$> ./mmap-rw.o /tmp/int-file

Credit: Advanced Linux Programming