Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of MAP_ANONYMOUS flag in mmap system call?

From the man page,

MAP_ANONYMOUS               The mapping is not backed by any file; its contents are initialized to zero.  The fd and offset arguments are ignored; however, some implementations  require               fd  to  be  -1  if  MAP_ANONYMOUS  (or  MAP_ANON)  is  specified, and portable applications should ensure this.  The use of MAP_ANONYMOUS in conjunction with               MAP_SHARED is only supported on Linux since kernel 2.4. 

What is the purpose of using MAP_ANONYMOUS? Any example would be good. Also From where the memory will be mapped?

It is written on man page that The use of MAP_ANONYMOUS in conjunction with MAP_SHARED is only supported on Linux since kernel 2.4. How can i share the memory mapped with MAP_ANONYMOUS with other process?

like image 277
Jagdish Avatar asked Dec 02 '15 12:12

Jagdish


People also ask

What does the Map_anonymous do in combination with mmap?

MAP_ANONYMOUS + MAP_SHARED: each call creates a distinct mapping that doesn't share pages with any other mapping. children inherit parent's mappings. no copy-on-write when someone else sharing the mapping writes on the shared mapping.

Where is Map_anonymous defined?

EDIT: It turns out the MAP_ANONYMOUS macro is defined in /usr/include/bits/mman.

What is the purpose of mmap?

The mmap() function is used for mapping between a process address space and either files or devices. When a file is mapped to a process address space, the file can be accessed like an array in the program.

What is FD in mmap?

mmap() is used for creating a memory mapping somewhere in virtual memory (somewhere which can be referenced to by the process issuing mmap). Specifying a file descriptor allows the memory to be swapped out to disk.


1 Answers

Anonymous mappings can be pictured as a zeroized virtual file. Anonymous mappings are simply large, zero-filled blocks of memory ready for use. These mappings reside outside of the heap, thus do not contribute to data segment fragmentation.

MAP_ANONYMOUS + MAP_PRIVATE:

  • every call creates a distinct mapping
  • children inherit parent's mappings
  • childrens' writes on the inherited mapping are catered in copy-on-write manner
  • the main purpose of using this kind of mapping is to allocate a new zeroized memory
  • malloc employs anonymous private mappings to serve memory allocation requests larger than MMAP_THRESHOLD bytes.
    typically, MMAP_THRESHOLD is 128kB.

MAP_ANONYMOUS + MAP_SHARED:

  • each call creates a distinct mapping that doesn't share pages with any other mapping
  • children inherit parent's mappings
  • no copy-on-write when someone else sharing the mapping writes on the shared mapping
  • shared anonymous mappings allow IPC in a manner similar to System V memory segments, but only between related processes

On Linux, there are two ways to create anonymous mappings:

  • specify MAP_ANONYMOUS flag and pass -1 for fd

        addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);      if (addr == MAP_FAILED)         exit(EXIT_FAILURE);   
  • open /dev/zero and pass this opened fd

        fd = open("/dev/zero", O_RDWR);        addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 

    (this method is typically used on systems like BSD, that do not have MAP_ANONYMOUS flag)

Advantages of anonymous mappings:
- no virtual address space fragmentation; after unmapping, the memory is immediately returned to the system
- they are modifiable in terms of allocation size, permissions and they can also receive advice just like normal mappings
- each allocation is a distinct mapping, separate from global heap

Disadvantages of anonymous mappings:
- size of each mapping is an integer multiple of system's page size, thus it can lead to wastage of address space
- creating and returning mappings incur more overhead than that of from the pre-allocated heap

if a program containing such mapping, forks a process, the child inherits the mapping. The following program demonstrates this kinda inheritance:

#ifdef USE_MAP_ANON #define _BSD_SOURCE #endif   #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/wait.h> #include <sys/mman.h> #include <fcntl.h> #include <unistd.h>  int main(int argc, char *argv[]) {     /*Pointer to shared memory region*/         int *addr;     #ifdef USE_MAP_ANON      /*Use MAP_ANONYMOUS*/                 addr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);           if (addr == MAP_FAILED) {               fprintf(stderr, "mmap() failed\n");               exit(EXIT_FAILURE);      }        #else        /*Map /dev/zero*/          int fd;         fd = open("/dev/zero", O_RDWR);           if (fd == -1) {             fprintf(stderr, "open() failed\n");         exit(EXIT_FAILURE);     }          addr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);         if (addr == MAP_FAILED) {             fprintf(stderr, "mmap() failed\n");             exit(EXIT_FAILURE);         }           if (close(fd) == -1) {          /*No longer needed*/             fprintf(stderr, "close() failed\n");             exit(EXIT_FAILURE);         } #endif         *addr = 1;      /*Initialize integer in mapped region*/          switch(fork()) {        /*Parent and child share mapping*/          case -1:             fprintf(stderr, "fork() failed\n");         exit(EXIT_FAILURE);          case 0:         /*Child: increment shared integer and exit*/              printf("Child started, value = %d\n", *addr);             (*addr)++;              if (munmap(addr, sizeof(int)) == -1) {                 fprintf(stderr, "munmap()() failed\n");                 exit(EXIT_FAILURE);             }              exit(EXIT_SUCCESS);           default:        /*Parent: wait for child to terminate*/               if (wait(NULL) == -1) {                 fprintf(stderr, "wait() failed\n");                 exit(EXIT_FAILURE);               }               printf("In parent, value = %d\n", *addr);                  if (munmap(addr, sizeof(int)) == -1) {                    fprintf(stderr, "munmap()() failed\n");                   exit(EXIT_FAILURE);                }                 exit(EXIT_SUCCESS); } 

Sources:
The Linux Programming Interface
Chapter 49: Memory Mappings,
Author: Michael Kerrisk

Linux System Programming (3rd edition)
Chapter 8: Memory Management,
Author: Robert Love

like image 107
nachiketkulk Avatar answered Sep 21 '22 21:09

nachiketkulk