Mapowanie pamięci

Wywołanie systemowe mmap () zapewnia mapowanie w wirtualnej przestrzeni adresowej procesu wywołującego, który mapuje pliki lub urządzenia w pamięci. Jest to dwojakiego rodzaju -

File mapping or File-backed mapping- To mapowanie mapuje obszar pamięci wirtualnej procesu na pliki. Oznacza to, że odczyt lub zapis w tych obszarach pamięci powoduje odczyt lub zapis pliku. To jest domyślny typ mapowania.

Anonymous mapping- To mapowanie mapuje obszar pamięci wirtualnej procesu bez wsparcia przez żaden plik. Zawartość jest inicjowana na zero. To mapowanie jest podobne do dynamicznej alokacji pamięci (malloc ()) i jest używane w niektórych implementacjach malloc () dla pewnych alokacji.

Pamięć w jednym mapowaniu procesu może być współdzielona z mapowaniami w innych procesach. Można to zrobić na dwa sposoby -

  • Kiedy dwa procesy mapują ten sam region pliku, współużytkują te same strony pamięci fizycznej.

  • Jeśli tworzony jest proces potomny, dziedziczy on mapowania rodzica i te mapowania odnoszą się do tych samych stron pamięci fizycznej, co strona nadrzędna. Po każdej zmianie danych w procesie podrzędnym zostaną utworzone różne strony dla procesu podrzędnego.

Gdy dwa lub więcej procesów współdzieli te same strony, każdy proces może zobaczyć zmiany zawartości strony wprowadzone przez inne procesy w zależności od typu mapowania. Typ mapowania może być prywatny lub udostępniony -

Private Mapping (MAP_PRIVATE) - Modyfikacje zawartości tego mapowania nie są widoczne dla innych procesów, a mapowanie nie jest przenoszone do podstawowego pliku.

Shared Mapping (MAP_SHARED) - Modyfikacje zawartości tego mapowania są widoczne dla innych procesów, a mapowanie jest przenoszone do pliku źródłowego.

#include <sys/mman.h>

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

Powyższe wywołanie systemowe zwraca początkowy adres mapowania w przypadku sukcesu lub MAP_FAILED w przypadku błędu.

Adres wirtualny może być określony przez użytkownika lub wygenerowany przez jądro (po przekazaniu addr jako NULL). Wskazana długość pola wymaga rozmiaru mapowania w bajtach. Pole prot wskazuje wartości ochrony pamięci, takie jak PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC, przeznaczone dla regionów, do których nie można uzyskać dostępu, odczytać, zapisać lub wykonać odpowiednio. Ta wartość może być pojedyncza (PROT_NONE) lub może być ORd z dowolną z trzech flag (ostatnie 3). Flagi pól wskazują typ odwzorowania albo MAP_PRIVATE albo MAP_SHARED. Pole „fd” wskazuje deskryptor pliku identyfikujący plik do odwzorowania, a pole „offset” oznacza punkt początkowy pliku, jeśli trzeba odwzorować cały plik, przesunięcie powinno wynosić zero.

#include <sys/mman.h>

int munmap(void *addr, size_t length);

Powyższe wywołanie systemowe zwraca 0 w przypadku sukcesu lub -1 w przypadku błędu.

Wywołanie systemowe munmap powoduje usunięcie mapowania regionu już zmapowanego w pamięci. Pole addr wskazuje początkowy adres odwzorowania, a długość wskazuje rozmiar w bajtach odwzorowania do usunięcia. Zwykle mapowanie i usuwanie mapowania będzie dotyczyło całych mapowanych regionów. Jeśli ma być inaczej, należy go albo skurczyć, albo przeciąć na dwie części. Jeśli addr nie ma żadnych mapowań, to wywołanie nie miałoby żadnego efektu i wywołanie zwróciło 0 (sukces).

Rozważmy przykład -

Step 1 - Wpisz do pliku znaki alfanumeryczne, jak pokazano poniżej -

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- Zmapuj zawartość pliku do pamięci za pomocą wywołania systemowego mmap (). To zwróci adres początkowy po zmapowaniu do pamięci.

Step 3- Uzyskaj dostęp do zawartości pliku za pomocą notacji tablicowej (można również uzyskać dostęp za pomocą notacji wskaźnika), ponieważ nie odczytuje kosztownego wywołania systemowego read (). Korzystając z mapowania pamięci, unikaj wielokrotnego kopiowania między przestrzenią użytkownika, buforami przestrzeni jądra i pamięcią podręczną buforów.

Step 4 - Powtarzaj czytanie zawartości pliku, aż użytkownik wpisze „-1” (oznacza koniec dostępu).

Step 5 - Wykonywanie czynności porządkujących, tj. Usuwanie mapowania zmapowanego obszaru pamięci (munmap ()), zamykanie pliku i usuwanie pliku.

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

Wynik

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