Mappatura della memoria

La chiamata di sistema mmap () fornisce la mappatura nello spazio degli indirizzi virtuali del processo chiamante che mappa i file o i dispositivi nella memoria. Questo è di due tipi:

File mapping or File-backed mapping- Questa mappatura mappa l'area della memoria virtuale del processo sui file. Ciò significa che la lettura o la scrittura in quelle aree di memoria provoca la lettura o la scrittura del file. Questo è il tipo di mappatura predefinito.

Anonymous mapping- Questa mappatura mappa l'area della memoria virtuale del processo senza il supporto di alcun file. I contenuti vengono inizializzati a zero. Questa mappatura è simile all'allocazione dinamica della memoria (malloc ()) e viene utilizzata in alcune implementazioni di malloc () per determinate allocazioni.

La memoria in una mappatura del processo può essere condivisa con le mappature in altri processi. Questo può essere fatto in due modi:

  • Quando due processi mappano la stessa regione di un file, condividono le stesse pagine di memoria fisica.

  • Se viene creato un processo figlio, eredita le mappature del genitore e queste mappature si riferiscono alle stesse pagine di memoria fisica di quella del genitore. In caso di modifica dei dati nel processo figlio, verranno create pagine diverse per il processo figlio.

Quando due o più processi condividono le stesse pagine, ogni processo può vedere le modifiche del contenuto della pagina apportate da altri processi a seconda del tipo di mappatura. Il tipo di mappatura può essere privato o condiviso -

Private Mapping (MAP_PRIVATE) - Le modifiche al contenuto di questa mappatura non sono visibili ad altri processi e la mappatura non viene trasferita al file sottostante.

Shared Mapping (MAP_SHARED) - Le modifiche al contenuto di questa mappatura sono visibili ad altri processi e la mappatura viene trasferita al file sottostante.

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

La chiamata di sistema precedente restituisce l'indirizzo iniziale della mappatura in caso di successo o MAP_FAILED in caso di errore.

L'indirizzo virtuale addr, può essere specificato dall'utente o generato dal kernel (dopo aver passato addr come NULL). La lunghezza del campo indicata richiede la dimensione della mappatura in byte. Il campo prot indica i valori di protezione della memoria come PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC destinati a regioni a cui non è possibile accedere, leggere, scrivere o eseguire rispettivamente. Questo valore può essere singolo (PROT_NONE) o può essere ORd con uno dei tre flag (gli ultimi 3). I flag di campo indicano il tipo di mappatura o MAP_PRIVATE o MAP_SHARED. Il campo 'fd' indica il descrittore di file che identifica il file da mappare e il campo 'offset' implica il punto di partenza del file, se è necessario mappare l'intero file, l'offset dovrebbe essere zero.

#include <sys/mman.h>

int munmap(void *addr, size_t length);

La chiamata di sistema precedente restituisce 0 in caso di successo o -1 in caso di errore.

La chiamata di sistema munmap, esegue l'annullamento della mappatura della regione già mappata in memoria. I campi addr indicano l'indirizzo iniziale della mappatura e la lunghezza indica la dimensione in byte della mappatura da non mappare. Di solito, la mappatura e l'annullamento della mappatura riguardano le intere regioni mappate. Se questo deve essere diverso, dovrebbe essere ridotto o tagliato in due parti. Se l'addr non ha alcuna mappatura questa chiamata non avrebbe effetto e la chiamata restituisce 0 (successo).

Consideriamo un esempio:

Step 1 - Scrivi in ​​file caratteri alfanumerici come mostrato di seguito -

0 1 2 25 26 27 28 29 30 31 32 33 34 35 36 37 38 59 60 61
A B C Z 0 1 2 3 4 5 6 7 8 9 A b c x y z

Step 2- Mappare il contenuto del file in memoria utilizzando la chiamata di sistema mmap (). Ciò restituirebbe l'indirizzo iniziale dopo la mappatura nella memoria.

Step 3- Accedi al contenuto del file utilizzando la notazione array (può anche accedere con notazione puntatore) poiché non legge la costosa chiamata di sistema read (). Utilizzando la mappatura della memoria, evitare di copiare più copie tra lo spazio utente, i buffer dello spazio del kernel e la cache del buffer.

Step 4 - Ripetere la lettura del contenuto del file fino a quando l'utente non immette "-1" (indica la fine dell'accesso).

Step 5 - Eseguire attività di pulizia, ad esempio, rimuovere la mappatura della regione di memoria mappata (munmap ()), chiudere il file e rimuovere il file.

/* Filename: mmap_test.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
void write_mmap_sample_data();

int main() {
   struct stat mmapstat;
   char *data;
   int minbyteindex;
   int maxbyteindex;
   int offset;
   int fd;
   int unmapstatus;
   write_mmap_sample_data();
   if (stat("MMAP_DATA.txt", &mmapstat) == -1) {
      perror("stat failure");
      return 1;
   }
   
   if ((fd = open("MMAP_DATA.txt", O_RDONLY)) == -1) {
      perror("open failure");
      return 1;
   }
   data = mmap((caddr_t)0, mmapstat.st_size, PROT_READ, MAP_SHARED, fd, 0);
   
   if (data == (caddr_t)(-1)) {
      perror("mmap failure");
      return 1;
   }
   minbyteindex = 0;
   maxbyteindex = mmapstat.st_size - 1;
   
   do {
      printf("Enter -1 to quit or ");
      printf("enter a number between %d and %d: ", minbyteindex, maxbyteindex);
      scanf("%d",&offset);
      if ( (offset >= 0) && (offset <= maxbyteindex) )
      printf("Received char at %d is %c\n", offset, data[offset]);
      else if (offset != -1)
      printf("Received invalid index %d\n", offset);
   } while (offset != -1);
   unmapstatus = munmap(data, mmapstat.st_size);
   
   if (unmapstatus == -1) {
      perror("munmap failure");
      return 1;
   }
   close(fd);
   system("rm -f MMAP_DATA.txt");
   return 0;
}

void write_mmap_sample_data() {
   int fd;
   char ch;
   struct stat textfilestat;
   fd = open("MMAP_DATA.txt", O_CREAT|O_TRUNC|O_WRONLY, 0666);
   if (fd == -1) {
      perror("File open error ");
      return;
   }
   // Write A to Z
   ch = 'A';
   
   while (ch <= 'Z') {
      write(fd, &ch, sizeof(ch));
      ch++;
   }
   // Write 0 to 9
   ch = '0';
   
   while (ch <= '9') {
      write(fd, &ch, sizeof(ch));
      ch++;
   }
   // Write a to z
   ch = 'a';
   
   while (ch <= 'z') {
      write(fd, &ch, sizeof(ch));
      ch++;
   }
   close(fd);
   return;
}

Produzione

Enter -1 to quit or enter a number between 0 and 61: 3 
Received char at 3 is D 
Enter -1 to quit or enter a number between 0 and 61: 28
Received char at 28 is 2 
Enter -1 to quit or enter a number between 0 and 61: 38 
Received char at 38 is c 
Enter -1 to quit or enter a number between 0 and 61: 59 
Received char at 59 is x 
Enter -1 to quit or enter a number between 0 and 61: 65 
Received invalid index 65 
Enter -1 to quit or enter a number between 0 and 61: -99 
Received invalid index -99 
Enter -1 to quit or enter a number between 0 and 61: -1