12.6. Обращение к объектам, отображенным в память

12.6. Обращение к объектам, отображенным в память

Когда в память отображается обычный файл, размер полученной области (второй аргумент вызова mmap), как правило, совпадает с размером файла. Например, в листинге 12.3 размер файла устанавливается равным размеру структуры shared вызовом write и это же значение размера области используется при отображении его в память. Однако эти два параметра — размер файла и размер области памяти, в которую он отображен, — могут и отличаться.

Для детального изучения особенностей функции mmap воспользуемся программой в листинге 12.6.

Листинг 12.6. Отображение файла: размер файла совпадает с размером области памяти

//shra/test1.c

1  #include "unpipc.h"

2  int

3  main(int argc, char **argv)

4  {

5   int fd, i;

6   char *ptr;

7   size_t filesize, mmapsize, pagesize;

8   if (argc != 4)

9    err_quit("usage: test1 <pathname> <filesize> <mmapsize>");

10  filesize = atoi(argv[2]);

11  mmapsize = atoi(argv[3]);

12  /* открытие файла, установка его размера */

13  fd = Open(argv[1], O_RDWR | O_CREAT | O_TRUNC, FILE_MODE);

14  Lseek(fd, filesize-1, SEEK_SET);

15  Write(fd, "", 1);

16  ptr = Mmap(NULL, mmapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

17  Close(fd);

18  pagesize = Sysconf(_SC_PAGESIZE);

19  printf("PAGESIZE = %ld ", (long) pagesize);

20  for (i = 0; i < max(filesize, mmapsize); i += pagesize) {

21   printf("ptr[*d] = %d ", i, ptr[i]);

22   ptr[i] = 1;

23   printf("ptr[%d] = %d ", i + pagesize – 1, ptr[i + pagesize – 1]);

24   ptr[i + pagesize – 1] = 1;

25  }

26  printf("ptr[%d] = %d ", i, ptr[i]);

27  exit(0);

28 }

Аргументы командной строки

8-11 Аргументы командной строки задают полное имя создаваемого и отображаемого в память файла, его размер и размер области памяти.

Создание, открытие, урезание файла; установка его размера

12-15 Если файл не существует, он будет создан. Если он существует, его длина будет установлена равной нулю. Затем размер файла устанавливается равным указанному размеру путем вызова lseek для установки текущей позиции, равной трe-буемому размеру минус 1 и записи 1 байта.

Отображение файла в память

16-17 Файл отображается в память, причем размер области задается последним аргументом командной строки. Затем дескриптор файла закрывается.

Вывод размера страницы памяти

18-19 Размер страницы памяти получается вызовом sysconf и выводится на экран.

Чтение и запись в область отображения

20-26 Считываются и выводятся данные из области памяти, в которую отображен файл. Считываются первый и последний байты каждой страницы этой области памяти. Все значения должны быть нулевыми. Затем первый и последний байты каждой страницы устанавливаются в 1. Одно из обращений к памяти может привести к отправке сигнала процессу, что приведет к его завершению. После завершения цикла for мы добавляем еще одно обращение к следующей странице памяти, что должно заведомо привести к ошибке и завершению пpoгрaммы (если ошибка не возникла раньше).

Рассмотрим первую ситуацию: размер файла совпадает с размером области памяти, но эта величина не кратна размеру страницы памяти в данной реализации:

solaris % ls –l foo

foo: No such file or directory

solaris % test1 foo 5000 5000

PAGESIZE = 4096

ptr[0] = 0

ptr[4095] = 0

ptr[4096] = 0

ptr[8191] = 0

Segmentation Fault(coredump)

solaris % ls-l foo

-rw-r--r-- 1 rstevens other1 5000 Mar 20 17:18 foo

solaris % od –b –A d foo

0000000 001 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000

0000016 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000

*

0004080 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 001

0004096 001 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000

0004112 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000

0005000

Размер страницы памяти составляет 4096 байт, и мы смогли обратиться ко всему содержимому второй страницы (индексы 4096-8191), но обращение к третьей странице (8192) приводит к отправке сигнала SIGSEGV, о чем интерпретатор оповещает сообщением Segmentation Fault. Хотя мы и установили значение ptr[8191] = 1, оно не было записано в файл и его размер остался равным 5000 байт. Ядро позволяет считывать и записывать данные в ту часть последней страницы, которая не относится к отображенному файлу (поскольку защита памяти осуществляется ядром постранично), но изменения в этой области памяти не будут скопированы в файл. А вот относящиеся к файлу изменения (индексы 0, 4095 и 4096) были скопированы в него, в чем мы убедились, воспользовавшись программой od (параметр –b при вызове последней указывает на необходимость выводить значения байтов в восьмеричном формате, а параметр –Ad позволяет выводить адреса в десятичном формате). На рис. 12.8 изображена схема памяти для данного примера. 

Рис. 12.8. Размер отображаемого файла совпадает с размером области памяти

Запустив этот пример в Digital Unix 4.0B, получим тот же результат, но размер страницы памяти в этой системе равняется 8192 байт:

alpha % ls –l foo

foo not found

alpha % test1 foo5000 5000

PAGESIZE = 8192

ptr[0] = 0

ptr[8191] = 0

Memory fault (coredump)

alpha % ls -l foo

-rw-r-r– 1 rstevens operator 5000 Mar 21 08:40 foo

Мы все так же можем обратиться к памяти за пределами отображенного файла, но не выходя за грaницы страницы памяти (индексы с 5000 по 8191). Обращение к ptr[8192] приводит к отправке SIGSEGV, на что мы и рассчитывали.

Вторая ситуация: размер области памяти (15000 байт) превышает размер файла (5000 байт):

solaris % rm foo

solaris % test1 foo 5000 15000

ptr[0] = 0

ptr[4095] = 0

ptr[4096] = 0

ptr[8191] = 0

Bus Error(coredump)

solaris % ls –l foo

-rw-r-r– 1 rstevens other1 5000 Mar 20 17:37 foo 

Рис. 12.9. Размер области памяти больше размера отображаемого файла

Полученный результат аналогичен результату предыдущего примера, в котором размер файла равнялся размеру области отображения (5000 байт). Однако в данном примере генерируется сигнал SIGBUS (о чем интерпретатор оповещает сообщением Bus Error), тогда как в предыдущем примере отправлялся сигнал SIGSEGV. Отличие в том, что SIGBUS означает выход за грaницы отображенного файла внутри области отображения, a SIGSEGV — выход за грaницы области. Этим примером мы показали, что ядро хранит информацию о размере отображенного объекта, даже несмотря на то, что его дескриптор закрыт. Ядро позволяет указать при вызове mmap размер области памяти, больший размера файла, но не позволяет обратиться к адресам в этой области (кроме остатка последней страницы, в которой еще имеется содержимое собственно файла — индексы с 5000 по 8191 в данном случае). На рис. 12.9 приведена иллюстрация к этому примеру. 

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

Листинг 12.7. Отображение увеличивающегося файла в память

//shm/test2.c

1  #include "unpipc.h"

2  #define FILE "test.data"

3  #define SIZE 32768

4  int

5  main(int argc, char **argv)

6  {

7   int fd, i;

8   char *ptr;

9   /* открытие, создание, урезание и установка размера файла, вызов mmap */

10  fd = Open(FILE, O_RDWR | O_CREAT | O_TRUNC, FILE_MODE);

11  ptr = Mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

12  for (i = 4096; i <= SIZE; i += 4096) {

13   printf("setting file size to %d ", i);

14   Ftruncate(fd, i);

15   printf("ptr[%d] = %d ", i-1, ptr[i-1]);

16  }

17  exit(0);

18 }

Открытие файла

9-11 Мы создаем файл, если он еще не существует, или урезаем его до нулевой длины, если он существует. Затем файл отображается в область объемом 32 768 байт, хотя его текущий размер равен нулю.

Увеличение размера файла

12-16 Мы увеличиваем размер файла на 4096 байт за один вызов ftruncate (раздел 13.3) и считываем из него последний байт в каждом проходе цикла.

Запустив эту программу, мы убедимся в возможности обращаться к новым данным по мере роста файла:

alpha % ls –l test.data

test.data: No such file or directory

alpha % test2

setting file size to 4096

ptr[4095] = 0

setting file size to 8192

ptr[8191] = 0

setting file size to 12288

ptr[12287] = 0

setting file size to 16384

ptr[16383] = 0

setting file size to 20480

ptr[20479] = 0

setting file size to 24576

ptr[24575] = 0

setting file size to 28672

ptr[28671] = 0

setting file size to 32768

ptr[32767] = 0

alpha % ls-l test.data

-rw-r--r-- 1 rstevens other1 32768 Mar 20 17:53 test.data

Этот пример показывает, что ядро всегда следит за размером отображаемого в память объекта (в данном примере это файл test.data), и мы всегда имеем возможность обратиться к байтам, лежащим внутри области, ограниченной размером файла и размером отображения. Те же результаты получаются при запуске этой программы в Solaris 2.6.

В этом разделе мы работали с отображением файлов в память с помощью mmap. В упражнении 13.1 нам придется немного изменить две наших программы для работы с разделяемой памятью Posix, и мы получим те же результаты.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Гаолян кы сын бо! Обращение к трудящимся

Из книги Журнал `Компьютерра` №729 автора Журнал «Компьютерра»

Гаолян кы сын бо! Обращение к трудящимся Авторы: Хозяин Лясао Хаобынь, Джерри Карпов-цзыБратья и сестры! Товарищи! Наступает светлый день для всей нашей необъятной родины. Сегодня, 4 апреля 2048 года, мы празднуем сорокалетие того дня, когда Китай наконец-то по праву вернул


4.1.2 Обращение к индексам

Из книги Архитектура операционной системы UNIX автора Бах Морис Дж

4.1.2 Обращение к индексам Ядро идентифицирует индексы по имени файловой системы и номеру индекса и выделяет индексы в памяти по запросам соответствующих алгоритмов. Алгоритм iget назначает индексу место для копии в памяти (Рисунок 4.3); он почти идентичен алгоритму getblk для


Доступ к объектам с помощью Web-служб

Из книги Обработка баз данных на Visual Basic®.NET автора Мак-Манус Джеффри П

Доступ к объектам с помощью Web-служб Итак, мы приступаем к работе на совершенно новом уровне, т.е. с использованием Web-служб. С самого начала Web-среда рассматривалась как способ передачи данных между двумя точками. Именно эта исходная концепция способствовала развитию и


Доступ к объектам

Из книги Основы AS/400 автора Солтис Фрэнк

Доступ к объектам Недостаточно просто найти объект. Чтобы получить к нему доступ или модифицировать объект, пользовательской или системной программе необходимы некоторые средства доступа. Для системных объектов эти средства находятся на уровне MI.OS/400 отвечает за


Права доступа к объектам

Из книги Системное программирование в среде Windows автора Харт Джонсон М

Права доступа к объектам К каждому объекту AS/400 может быть предоставлено восемь видов доступа, а именно:•право на оперирование объектом разрешает просматривать описание объекта и использовать объект соответственно имеющимся у пользователя правам[ 57 ];право на


Права объектов и доступ к объектам

Из книги Программирование на языке Ruby [Идеология языка, теория и практика применения] автора Фултон Хэл

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


8.1.20. Обращение массива

Из книги Сетевые средства Linux автора Смит Родерик В.

8.1.20. Обращение массива Чтобы переставить элементы массива в обратном порядке, воспользуйтесь методами reverse или reverse!:inputs = ["red", "green", "blue"]outputs = inputs.reverse # ["green","blue","red"]priorities = %w(eat sleep code)priorities.reverse! #


Обращение к элементам страницы

Из книги Технология XSLT автора Валиков Алексей Николаевич

Обращение к элементам страницы Объект document имеет несколько полезных методов, которые можно использовать в скриптах. Но главное его значение - предоставление доступа к отдельным элементам Web-страницы.Как же можно добраться до отдельного элемента страницы?Прежде всего,


Ограничение доступа к разделяемым объектам

Из книги VBA для чайников автора Каммингс Стив

Ограничение доступа к разделяемым объектам Samba использует различные средства контроля доступа к серверу. В качестве примера можно привести уже упоминавшиеся параметры hosts allow и hosts deny и, конечно же, модель аутентификации, согласно которой пользователь должен указывать


Обращение ссылок по ID /IDREF

Из книги C++. Сборник рецептов автора Диггинс Кристофер

Обращение ссылок по ID/IDREF Функция id позволяет отыскать в документе элементы по заданным значениями ID-атрибутов. Это особенно полезно при работе с IDREF-атрибутами, которые ссылаются на ID-атрибуты: можно с легкостью выбрать элементы, на которые ссылается текущий элемент.


4.5. Обращение строк

Из книги Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ автора Борри Хелен

4.5. Обращение строк ПроблемаТребуется обратить (реверсировать) строку.РешениеЧтобы обратить строку «на месте», не используя временной строки, используйте шаблон функции reverse из заголовочного файла <algorithm>:std::reverse(s.begin(), s.end());Обсуждениеreverse работает очень просто: она


Привилегии к объектам

Из книги автора

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