Cartographie de la mémoire

L'appel système mmap () fournit un mappage dans l'espace d'adressage virtuel du processus appelant qui mappe les fichiers ou les périphériques en mémoire. Ceci est de deux types -

File mapping or File-backed mapping- Ce mappage mappe la zone de la mémoire virtuelle du processus aux fichiers. Cela signifie que la lecture ou l'écriture dans ces zones de la mémoire entraîne la lecture ou l'écriture du fichier. Il s'agit du type de mappage par défaut.

Anonymous mapping- Ce mappage mappe la zone de la mémoire virtuelle du processus sans sauvegarde par aucun fichier. Le contenu est initialisé à zéro. Ce mappage est similaire à l'allocation de mémoire dynamique (malloc ()) et est utilisé dans certaines implémentations de malloc () pour certaines allocations.

La mémoire dans un mappage de processus peut être partagée avec des mappages dans d'autres processus. Cela peut être fait de deux manières -

  • Lorsque deux processus mappent la même région d'un fichier, ils partagent les mêmes pages de mémoire physique.

  • Si un processus enfant est créé, il hérite des mappages du parent et ces mappages font référence aux mêmes pages de mémoire physique que celle du parent. Lors de tout changement de données dans le processus enfant, différentes pages seraient créées pour le processus enfant.

Lorsque deux processus ou plus partagent les mêmes pages, chaque processus peut voir les modifications du contenu de la page effectuées par d'autres processus en fonction du type de mappage. Le type de mappage peut être privé ou partagé -

Private Mapping (MAP_PRIVATE) - Les modifications apportées au contenu de ce mappage ne sont pas visibles pour les autres processus et le mappage n'est pas transporté vers le fichier sous-jacent.

Shared Mapping (MAP_SHARED) - Les modifications apportées au contenu de ce mappage sont visibles par les autres processus et le mappage est porté au fichier sous-jacent.

#include <sys/mman.h>

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

L'appel système ci-dessus renvoie l'adresse de début du mappage en cas de succès ou MAP_FAILED en cas d'erreur.

L'adresse d'adresse virtuelle peut être soit spécifiée par l'utilisateur, soit générée par le noyau (en passant l'adr comme NULL). La longueur de champ indiquée nécessite la taille du mappage en octets. Le champ prot indique des valeurs de protection de la mémoire telles que PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC destinées à des régions qui ne peuvent pas être accédées, lues, écrites ou exécutées respectivement. Cette valeur peut être unique (PROT_NONE) ou peut être ORd avec l'un des trois indicateurs (3 derniers). Les indicateurs de champ indiquent le type de mappage soit MAP_PRIVATE ou MAP_SHARED. Le champ 'fd' indique le descripteur de fichier identifiant le fichier à mapper et le champ 'offset' implique le point de départ du fichier, si besoin de mapper le fichier entier, l'offset doit être nul.

#include <sys/mman.h>

int munmap(void *addr, size_t length);

L'appel système ci-dessus renvoie 0 en cas de succès ou -1 en cas d'erreur.

L'appel système munmap, effectue le démappage de la région déjà mappée en mémoire. Les champs addr indiquent l'adresse de début du mappage et la longueur indique la taille en octets du mappage à démapper. Habituellement, le mappage et le démappage concerneraient toutes les régions mappées. Si cela doit être différent, alors il doit être rétréci ou coupé en deux parties. Si l'adresse n'a pas de mappage, cet appel n'aurait aucun effet et l'appel renvoie 0 (succès).

Prenons un exemple -

Step 1 - Écrire dans le fichier les caractères alphanumériques comme indiqué ci-dessous -

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- Mappez le contenu du fichier en mémoire à l'aide de l'appel système mmap (). Cela renverrait l'adresse de départ après avoir été mappée dans la mémoire.

Step 3- Accédez au contenu du fichier en utilisant la notation de tableau (peut également accéder avec la notation de pointeur) car ne lit pas l'appel système read () coûteux. À l'aide du mappage de mémoire, évitez les copies multiples entre l'espace utilisateur, les tampons d'espace du noyau et le cache de tampon.

Step 4 - Répéter la lecture du contenu du fichier jusqu'à ce que l'utilisateur entre «-1» (signifie la fin de l'accès).

Step 5 - Effectuer des activités de nettoyage, c'est-à-dire démapper la région de mémoire mappée (munmap ()), fermer le fichier et supprimer le fichier.

/* 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;
}

Production

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