учреждениям, так и коммерческим организациям. Поскольку основная
часть системы поставлялась в исходных текстах, написанных на
языке С, опытным программистам не требовалось детальной
документации, чтобы разобраться в архитектуре UNIX. С ростом
популярности микропроцессоров
...
Файлы, отображаемые в памяти
Системный вызов mmap(2) предоставляет механизм доступа к файлам, альтернативный вызовам read(2) и write(2). С помощью этого вызова процесс имеет возможность отобразить участки файла в собственное адресное пространство. После этого данные файла могут быть получены или записаны путем чтения или записи в память. Функция mmap(2) определяется следующим образом:
#include <sys/types.h>
#include <sys/mman.h>
caddr_t mmap(caddr_t addr, size_t len, int prot,
int flags, int fildes, off_t off);
Этот вызов задает отображение len байтов файла с дескриптором fildes, начиная со смещения off, в область памяти со стартовым адресом addr. Разумеется, перед вызовом mmap(2) файл должен быть открыт с помощью функции open(2). Аргумент prot определяет права доступа к области памяти, которые должны соответствовать правам доступа к файлу, указанным в системном вызове open(2). В табл. 2.12 приведены возможные значения аргумента prot и соответствующие им права доступа к файлу. Возможно логическое объединение отдельных значений prot. Так значение PROT_READ | PROT_WRITE соответствует доступу O_RDWR к файлу.
Таблица 2.12. Права доступа к области памяти
| Значение аргумента prot | Описание | Права доступа к файлу |
|---|---|---|
PROT_READ |
Область доступна для чтения | r |
PROT_WRITE |
Область доступна для записи | w |
PROT_EXEC |
Область доступна для исполнения | x |
PROT_NONE |
Область недоступна | - |
Обычно значение addr задается равным 0, что позволяет операционной системе самостоятельно выбрать виртуальный адрес начала области отображения. В любом случае, при успешном завершении возвращаемое системным вызовом значение определяет действительное расположение области памяти.
Операционная система округляет значение len до следующей страницы виртуальной памяти.[19] Например, если размер файла 96 байтов, а размер страницы 4 Кбайт, то система все равно выделит область памяти размером 4096 байтов. При этом 96 байтов займут собственно данные файла, а остальные 4000 байтов будут заполнены нулями. Процесс может модифицировать и оставшиеся 4000 байтов, но эти изменения не отразятся на содержимом файла. При обращении к участку памяти, лежащему за пределами файла, ядро отправит процессу сигнал SIGBUS[20]. Несмотря на то что область памяти может превышать фактический размер файла, процесс не имеет возможности изменить его размер.
Использование права на исполнение (prot = PROT_EXEC) позволяет процессу определить собственный механизм загрузки кода. В частности, такой подход используется редактором динамических связей при загрузке динамических библиотек, когда библиотека отображается в адресное пространство процесса. Значение PROT_NONE позволяет приложению определить собственные механизмы контроля доступа к разделяемым объектам (например, к разделяемой памяти), разрешая или запрещая доступ к области памяти.
Аргумент flags определяет дополнительные особенности управления областью памяти. В табл. 2.13 приведены возможные типы отображения, определяемые аргументом flags.
Таблица 2.13. Типы отображения
| Значение аргумента flags | Описание |
|---|---|
MAP SHARED |
Область памяти может совместно использоваться несколькими процессами |
MAP PRIVATE |
Область памяти используется только вызывающим процессом |
MAP_FIXED |
Требует выделения памяти, начиная точно с адреса addr |
MAP_NORESERVE |
He требует резервирования области свопинга |
В случае указания MAP_PRIVATE, для процесса, определившего этот тип отображения, будет создана собственная копия страницы памяти, которую он пытается модифицировать. Заметим, что копия будет создана только при вызове операции записи, до этого остальные процессы, определившие тип отображения как MAP_SHARED могут совместно использовать одну и ту же область памяти.
Не рекомендуется использовать флаг MAP_FIXED, т.к. это не позволяет системе максимально эффективно распределить память. В случае отсутствия этого флага, ядро пытается выделить область памяти, начиная с адреса наиболее близкого к значению addr. Если же значение addr установлено равным 0, операционная система получает полную свободу в размещении области отображения.
Отображение автоматически снимается при завершении процесса. Процесс также может явно снять отображение с помощью вызова munmap(2). Закрытие файла не приводит к снятию отображения. Следует отметить, что снятие отображения непосредственно не влияет на отображаемый файл, т. е. содержимое страниц области отображения не будет немедленно записано на диск. Обновление файла производится ядром согласно алгоритмам управления виртуальной памятью. В то же время в ряде систем существует функция msync(3C), которая позволяет синхронизировать обновление памяти с обновлением файла на диске.[21]
В качестве примера приведем упрощенную версию утилиты cp(1), копирующую один файл в другой с использованием отображения файла в память.
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
main(int argc, char *argv[]) {
int fd_src, fd_dst;
caddr_t addr_src, addr_dst;
struct stat filestat;
/* Первый аргумент - исходный файл, второй - целевой */
20
Если быть более точным, сигнал посылается процессу, когда происходит обращение к странице памяти, на которую не отображается ни один из участков файла. Таким образом, в приведенном примере сигнал процессу не будет отправлен.
21
На самом деле