Вызов mmap() позволяет отображать не только обычные файлы, хранящиеся на диске, но и содержимое различных физических и виртуальных устройств, таких как жесткие и оптические диски или /dev/mem.

Файл, на который ссылается дескриптор fd, должен быть открыт с правами доступа, соответствующими значениям аргументов prot и flags. В частности, файл всегда должен быть доступен для чтения, а если в flags указаны флаги PROT_WRITE и MAP_SHARED, то также должен позволять запись. Аргумент offset обозначает начальный байт участка отображаемого файла и должен быть кратным размеру страницы в системе. Если он равен 0, то файл будет отображаться с самого начала. Аргумент length обозначает количество байтов, которое нужно отобразить. Сочетание ffset и length позволяет определить тот участок файла, что будет отображен в память (рис. 45.1).

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

45.4.1. Приватные файловые отображения

Наиболее часто приватные файловые отображения используются в следующих целях.

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

Исполняемый текстовый сегмент обычно защищен маской PROT_READ | PROT_EXEC, которая позволяет только чтение и выполнение, но при его отображении вместо MAP_SHARED применяется флаг MAP_PRIVATE. Это делается для того, чтобы отладчики или самомодифицирующиеся программы, вносящие изменения в программный код (предварительно откорректировав защиту памяти), не могли повлиять на исходный исполняемый файл или другие процессы.

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

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

Рис. 45.1. Структура файла, отображенного в память

45.4.2. Разделяемые файловые отображения

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

Разделяемые файловые отображения используются для двух задач: отображения ввода/вывода в память и межпроцессного взаимодействия. Каждый из этих случаев будет рассмотрен ниже.

Рис. 45.2. Два процесса, совместно отображающие один и тот же участок файла

Отображение ввода/вывода в память

Поскольку содержимое разделяемого файлового отображения берется из файла, в который возвращаются любые изменения, внесенные в само отображение, можно выполнять файловый ввод/вывод, просто работая с байтами памяти, — все изменения будут автоматически применены ядром к исходному файлу (обычно для преобразования содержимого отображения создается структура данных, соответствующая содержимому файла). Такой подход называется отображением ввода/вывода в память и составляет альтернативу использованию вызовов read() и write() для чтения и записи файлов.

Отображение ввода/вывода в память имеет два потенциальных преимущества:

• непосредственная работа с памятью вместо применения системных вызовов read() и write() позволяет упростить логику некоторых приложений;

• в ряде случаев это может улучшить производительность ввода/вывода по сравнению с использованием традиционных системных вызовов.

Причины, по которым отображение ввода/вывода в память может привести к улучшению производительности, заключаются в следующем.

Перейти на страницу:

Похожие книги