Отображение памяти

Системный вызов mmap () обеспечивает отображение в виртуальном адресном пространстве вызывающего процесса, который отображает файлы или устройства в память. Это двух типов -

Отображение файла или отображение на основе файла - это отображение отображает область виртуальной памяти процесса в файлы. Это означает, что чтение или запись в эти области памяти приводит к чтению или записи файла. Это тип отображения по умолчанию.

Анонимное сопоставление - это сопоставление отображает область виртуальной памяти процесса без поддержки какого-либо файла. Содержимое инициализируется до нуля. Это отображение похоже на динамическое распределение памяти (malloc ()) и используется в некоторых реализациях malloc () для определенных распределений.

Память в одном отображении процесса может использоваться совместно с отображениями в других процессах. Это можно сделать двумя способами -

  • Когда два процесса отображают одну и ту же область файла, они совместно используют одни и те же страницы физической памяти.

  • Если дочерний процесс создан, он наследует сопоставления родителя, и эти сопоставления ссылаются на те же страницы физической памяти, что и родительский. При любом изменении данных в дочернем процессе будут созданы разные страницы для дочернего процесса.

Когда два или более процессов совместно используют одни и те же страницы, каждый процесс может видеть изменения содержимого страницы, сделанные другими процессами, в зависимости от типа отображения. Тип отображения может быть частным или общим -

Частное сопоставление (MAP_PRIVATE) - изменения содержимого этого сопоставления не видны другим процессам, и сопоставление не переносится в базовый файл.

Общее сопоставление (MAP_SHARED) - изменения содержимого этого сопоставления видны другим процессам, и сопоставление переносится в базовый файл.

#include <sys/mman.h>

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

Приведенный выше системный вызов возвращает начальный адрес сопоставления в случае успеха или MAP_FAILED в случае ошибки.

Виртуальный адрес addr может быть задан пользователем или сгенерирован ядром (при передаче addr как NULL ). Указанная длина поля требует размера отображения в байтах. Поле prot указывает значения защиты памяти, такие как PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC, предназначенные для областей, к которым нельзя получить доступ, прочитать, записать или выполнить соответственно. Это значение может быть одинарным (PROT_NONE) или ORd с любым из трех флагов (последние 3). Флаги поля указывают тип отображения либо MAP_PRIVATE, либо MAP_SHARED. Поле «fd» указывает дескриптор файла, идентифицирующий файл, который должен быть отображен, а поле «смещение» подразумевает начальную точку файла, если необходимо отобразить весь файл, смещение должно быть равно нулю.

#include <sys/mman.h>

int munmap(void *addr, size_t length);

Приведенный выше системный вызов возвращает 0 в случае успеха или -1 в случае ошибки.

Системный вызов munmap, выполняет сопоставление уже отображенной области памяти. Поля addr указывают начальный адрес отображения, а длина указывает размер в байтах сопоставления, которое должно быть отображено. Как правило, сопоставление и снятие сопоставления было бы для всех отображаемых областей. Если это должно быть иначе, то это должно быть или сжато или сокращено на две части. Если адрес не имеет отображений, этот вызов не будет иметь эффекта, и вызов вернет 0 (успех).

Давайте рассмотрим пример -

Шаг 1 - Запишите в файл буквенно-цифровые символы, как показано ниже -

0 1 2 ... 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ... 59 60 61
В С ... Z 0 1 2 3 4 5 6 7 8 9 б с ... Икс Y Z

Шаг 2 - отобразить содержимое файла в память с помощью системного вызова mmap (). Это вернет начальный адрес после сопоставления в памяти.

Шаг 3 - Доступ к содержимому файла с использованием нотации массива (можно также получить доступ с нотацией указателя), так как не читает дорогой системный вызов read () Используя отображение памяти, избегайте многократного копирования между пользовательским пространством, буферами пространства ядра и буферным кешем.

Шаг 4 - Повторяйте чтение содержимого файла, пока пользователь не введет «-1» (означает конец доступа).

Шаг 5 - Выполните действия по очистке, т. Е. Отключите отображенную область памяти (munmap ()), закройте файл и удалите файл.

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

Выход

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