на главную | войти | регистрация | DMCA | контакты | справка | donate |      

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Э Ю Я


моя полка | жанры | рекомендуем | рейтинг книг | рейтинг авторов | впечатления | новое | форум | сборники | читалки | авторам | добавить



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

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 изображена схема памяти для данного примера. 

UNIX: взаимодействие процессов

Рис. 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 

UNIX: взаимодействие процессов

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


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

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


Вывод размера страницы памяти | UNIX: взаимодействие процессов | Листинг 12.7. Отображение увеличивающегося файла в память