web-dev-qa-db-fra.com

Quel est le but de l'indicateur MAP_ANONYMOUS dans l'appel système mmap?

Depuis la page man,

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.

À quoi sert l'utilisation de MAP_ANONYMOUS? Tout exemple serait bon. D'où la mémoire sera mappée?

Il est écrit sur la page man que The use of MAP_ANONYMOUS in conjunction with MAP_SHARED is only supported on Linux since kernel 2.4. Comment puis-je partager la mémoire mappée avec MAP_ANONYMOUS avec un autre processus?

21
GeekyJ

Les mappages anonymes peuvent être représentés comme un fichier virtuel mis à zéro. Les mappages anonymes sont simplement de grands blocs de mémoire remplis de zéro prêts à l'emploi. Ces mappages résident en dehors du tas, donc ne contribuent pas à la fragmentation du segment de données.

MAP_ANONYMOUS + MAP_PRIVATE:

  • chaque appel crée un mappage distinct
  • les enfants héritent des mappages des parents
  • les écritures des enfants sur le mappage hérité sont traitées de manière copie sur écriture
  • l'objectif principal de l'utilisation de ce type de mappage est d'allouer une nouvelle mémoire à zéro
  • malloc utilise des mappages privés anonymes pour traiter les demandes d'allocation de mémoire supérieures aux octets MMAP_THRESHOLD.
    généralement, MMAP_THRESHOLD est de 128 Ko.

MAP_ANONYMOUS + MAP_SHARED:

  • chaque appel crée un mappage distinct qui ne partage pas de pages avec aucun autre mappage
  • les enfants héritent des mappages des parents
  • pas de copie sur écriture lorsque quelqu'un d'autre partageant le mappage écrit sur le mappage partagé
  • les mappages anonymes partagés permettent IPC d'une manière similaire aux segments de mémoire System V, mais uniquement entre les processus associés

Sous Linux, il existe deux façons de créer des mappages anonymes:

  • spécifiez l'indicateur MAP_ANONYMOUS et passez -1 pour fd

        addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); 
        if (addr == MAP_FAILED)
            exit(EXIT_FAILURE);  
    
  • ouvrez/dev/zero et passez ce fd ouvert

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

    (cette méthode est généralement utilisée sur des systèmes comme BSD, qui n'ont pas d'indicateur MAP_ANONYMOUS)

Avantages des mappages anonymes:
- pas de fragmentation de l'espace d'adressage virtuel; après démappage, la mémoire est immédiatement renvoyée au système
- ils sont modifiables en termes de taille d'allocation, d'autorisations et ils peuvent également recevoir des conseils tout comme les mappings normaux
- chaque allocation est un mappage distinct, distinct du tas global

Inconvénients des mappages anonymes:
- la taille de chaque mappage est un multiple entier de la taille de page du système, ce qui peut entraîner un gaspillage de l'espace d'adressage
- la création et le renvoi de mappages entraînent plus de frais généraux que ceux du tas préalloué

si un programme contenant un tel mappage opère un processus, l'enfant hérite du mappage. Le programme suivant illustre ce genre d'héritage:

#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:
L'interface de programmation Linux
Chapitre 49: Mappages de mémoire,
Auteur: Michael Kerrisk

Programmation système Linux (3e édition)
Chapitre 8: Gestion de la mémoire,
Auteur: Robert Love

34
nachiketkulk