mmap, munmap -
отображает
файлы или
устройства
в памяти,
или
удаляет их
отображение
Standard C library (
libc,
-lc)
#include <sys/mman.h>
void *mmap(void addr[.length], size_t length, int prot, int flags,
int fd, off_t offset);
int munmap(void addr[.length], size_t length);
Информацию
по
требованиям
макроса
тестирования
свойств
смотрите в
разделе
ЗАМЕЧАНИЯ.
Вызов
mmap()
создаёт
новое
отображение
в
виртуальном
адресном
пространстве
вызывающего
процесса.
Адрес
начала
нового
отображения
указывается
в
addr. В
аргументе
length задаётся
длина
отображения
(должна
быть
больше 0).
Если
значение
addr
равно NULL, то
ядро само
выбирает
адрес
(выровненный
по
странице),
по
которому
создаётся
отображение;
это
наиболее
переносимый
метод
создания
нового
отображения.
Если
значение
addr
не равно NULL,
то ядро
учитывает
это при
размещении
отображения;
в Linux ядро
выберет
ближайшую
к границе
страницу
(но всегда
выше или
равною
значению,
заданному
в
/proc/sys/vm/mmap_min_addr) и
попытается
создать
отображение.
Если по
этому
адресу уже
есть
отображение,
то ядро
выберет
новый
адрес,
который
может и не
зависеть
от
подсказки.
Адрес
нового
отображения
возвращается
как
результат
вызова.
Содержимое
файлового
отображения
(в отличие
от
анонимного
отображения;
смотрите
MAP_ANONYMOUS далее)
инициализируется
данными из
файла (или
объекта), на
который
указывает
файловый
дескриптор
fd, длиной
length
байт,
начиная со
смещения
offset.
Значение
offset
должно
быть
кратно
размеру
(возвращается
sysconf(_SC_PAGE_SIZE))
страницы.
После
возврата
из вызова
mmap() файловый
дескриптор
fd может
быть
немедленно
закрыт без
признания
отображения
недействительным.
В
аргументе
prot
указывается
желаемая
защита
памяти
отображения
(не должна
конфликтовать
с режимом
открытого
файла).
Значением
может быть
PROT_NONE или
побитово
сложенные (OR)
следующие
флаги:
- PROT_EXEC
- Страницы
доступны
для
исполнения.
- PROT_READ
- Страницы
доступны
для
чтения.
- PROT_WRITE
- Страницы
доступны
для
записи.
- PROT_NONE
- Страницы
недоступны.
В
аргументе
flags задаётся
будут ли
изменения
отображения
видимы
другим
процессам,
отображающим
ту же
область, и
будут ли
изменения
перенесены
в
отображённый
файл.
Данное
поведение
определяется
в
flags одним
из
следующих
значений:
- MAP_SHARED
- Сделать
отображение
общим.
Изменения
отображения
видимы
всем
процессам,
отображающим
ту же
область и
(если
отображение
выполняется
из файла)
изменения
заносятся
в
отображённый
файл (для
более
точного
контроля
над
изменениями
файла
нужно
использовать
msync(2)).
-
MAP_SHARED_VALIDATE
(начиная с Linux
4.15)
- Данный
флаг
представляет
тоже, что и
MAP_SHARED,
отображения
MAP_SHARED
игнорируют
неизвестные
флаги flags.
Если же
отображение
создаётся
с MAP_SHARED_VALIDATE, ядро
проверят,
что ему
известны
все
переданные
флаги и
завершает
отображение
ошибкой
EOPNOTSUPP, если
есть
неизвестные
флаги. Этот
тип
отображения
также
требуется
для
использования
некоторых
флагов
отображения
(например,
MAP_SYNC).
- MAP_PRIVATE
- Создать
закрытое
отображение
с
механизмом
копирования
при записи.
Изменения
отображения
невидимы
другим
процессам,
отображающим
тот же
файл, и сам
файл не
изменяется.
Не
определено,
будут ли
видимы в
отображённой
области
изменения
в файле,
сделанные
после
вызова mmap().
Флаги
MAP_SHARED и
MAP_PRIVATE описаны
в POSIX.1-2001 и POSIX.1-2008. Флаг
MAP_SHARED_VALIDATE
является
расширением
Linux.
Кроме
этого в
flags
могут быть
указаны
(побитовым
сложением):
-
MAP_32BIT
(начиная с Linux
2.4.20, 2.6)
- Поместить
отображение
в первые 2
гигабайта
адресного
пространства
процесса.
Этот флаг
поддерживается
только на
архитектуре
x86-64 для
64-битных
программ.
Он был
добавлен
для
размещения
стеков
нитей в
первых 2 ГБ
памяти, что
даёт
увеличение
производительности
при
переключения
контекста
на
некоторых
первых
64-битных
процессорах.
В
современных
процессорах
x86-64 такой
проблемы с
производительностью
больше нет,
поэтому на
таких
системах
данный
флаг
больше не
требуется.
Он
игнорируется,
если
указан
флаг MAP_FIXED.
- MAP_ANON
- Synonym for MAP_ANONYMOUS; provided for
compatibility with other implementations.
- MAP_ANONYMOUS
- The mapping is not backed by any file; its contents are
initialized to zero. The fd argument is ignored; however, some
implementations require fd to be -1 if MAP_ANONYMOUS (or
MAP_ANON) is specified, and portable applications should ensure
this. The offset argument should be zero. Support for
MAP_ANONYMOUS in conjunction with MAP_SHARED was added in
Linux 2.4.
- MAP_DENYWRITE
- This flag is ignored. (Long ago—Linux 2.0 and
earlier—it signaled that attempts to write to the underlying file
should fail with ETXTBSY. But this was a source of
denial-of-service attacks.)
- MAP_EXECUTABLE
- Этот
флаг
игнорируется.
- MAP_FILE
- Флаг для
совместимости,
игнорируется.
- MAP_FIXED
- Не
учитывать
addr как
подсказку:
помещать
отображение
точно по
этому
адресу.
Значение
addr должно
быть
выровнено
соответствующим
образом: на
большинстве
архитектур
оно должно
быть
кратно
размеру
страницы;
однако
некоторые
архитектуры
могут
накладывать
дополнительные
ограничения.
Если
область
памяти,
задаваемая
addr и length,
перекрывается
со
страницами
существующих
отображений,
то
перекрывающаяся
часть
существующих
отображений
будет
отброшена.
Если
заданный
адрес не
может быть
использован,
то вызов mmap()
завершается
ошибкой.
- Software that aspires to be portable should use the
MAP_FIXED flag with care, keeping in mind that the exact layout of
a process's memory mappings is allowed to change significantly between
Linux versions, C library versions, and operating system releases.
Carefully read the discussion of this flag in NOTES!
-
MAP_FIXED_NOREPLACE
(начиная с Linux
4.17)
- Данный
флаг
действует
схожим с MAP_FIXED
образом
при
контроле
addr, но в
отличие от
него, флаг
MAP_FIXED_NOREPLACE
никогда не
разделяет
уже
существующий
отображённый
диапазон.
Если
запрошенный
диапазон
пересекается
с
существующим
отображением,
то такой
вызов
завершается
ошибкой EEXIST.
Поэтому
данный
флаг можно
использовать
как
атомарную
(если есть
другие
нити)
попытку
отображения
адресного
диапазона:
для одной
нити она
закончится
успешно;
все
остальные
получат
ошибку.
- Note that older kernels which do not recognize the
MAP_FIXED_NOREPLACE flag will typically (upon detecting a collision
with a preexisting mapping) fall back to a “non-
MAP_FIXED” type of behavior: they will return an address
that is different from the requested address. Therefore,
backward-compatible software should check the returned address against the
requested address.
- MAP_GROWSDOWN
- Этот
флаг
используется
для стеков.
Для
виртуальной
системы
памяти
ядра он
обозначает,
что
отображение
должно
расширяться
вниз по
памяти.
Возвращаемый
адрес
указывает
на одну
страницу
ниже
области
памяти,
которая в
действительности
создаётся
в
виртуальном
адресном
пространстве
процесса.
Обращение
к адресу
ниже
«защитной»
страницы
отображения
приведёт к
расширению
отображения
на
страницу.
Увеличение
таким
способом
можно
повторять
до тех пор,
пока рост
отображения
страницы
верхним
концом не
достигнет
следующего
нижнего
отображения,
при таком
обращении
к
«защитной»
страницы
возникнет
сигнал SIGSEGV.
-
MAP_HUGETLB
(начиная с Linux
2.6.32)
- Выделять
отображение
используя
«огромные
страницы».
Дополнительную
информацию
смотрите в
файле
исходного
кода ядра Linux
Documentation/admin-guide/mm/hugetlbpage.rst, а
также
следующее
дополнение.
-
MAP_HUGE_2MB, MAP_HUGE_1GB
(начиная с Linux
3.8)
- Используется
как
дополнение
к MAP_HUGETLB для
выбора
размера
страницы hugetlb
(2 МБ и 1 ГБ,
соответственно),
сработает
только в
системе
которая
поддерживает
различные
размеры
больших
страниц.
- Вообще,
желаемый
размер
огромной
страницы
можно
настроить
закодировав
логарифм 2
от
желаемого
размера
страницы в
шести
битах со
смещением
MAP_HUGE_SHIFT
(значение
нуля в этом
битовом
поле
означает
выбор
значения
огромной
страницы
по
умолчанию;
это
значение
можно
найти в
поле Hugepagesize
просмотрев
файл /proc/meminfo).
Таким
образом
две
показанные
выше
константы
определены
как:
-
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
- Рабочий
диапазон
страниц
огромного
размера
может быть
обнаружен,
перечислив
подкаталоги
в /sys/kernel/mm/hugepages.
-
MAP_LOCKED
(начиная с Linux
2.5.37)
- Пометить
отображаемую
область
как
заблокированную
таким же
образом
как с
помощью mlock(2).
Данная
реализация
будет
пытаться
заполнить
(предотказ)
область
полностью,
но вызов mmap()
не
завершится
ошибкой ENOMEM,
если это не
удастся
сделать.
Поэтому
действительные
отказы
могут
произойти
позднее.
Такой
алгоритм
не
совпадает
с mlock(2). Нужно
использовать
mmap() плюс mlock(2),
если
действительные
отказы
недопустимы
после
инициализации
отображения.
В старых
ядрах флаг
MAP_LOCKED
игнорируется.
-
MAP_NONBLOCK
(начиная с Linux
2.5.46)
- Данный
флаг имеет
смысл
только
вместе с
MAP_POPULATE. Не
выполнять
упреждающее
чтение:
только
создать
записи в
таблице
страниц
для
страниц,
которые
уже есть
ОЗУ.
Начиная с Linux
2.6.23 этот флаг
приводит к
тому, что
выполнение
работы MAP_POPULATE
отменяется.
Когда-нибудь
комбинация
MAP_POPULATE и MAP_NONBLOCK
может быть
реализована
заново.
- MAP_NORESERVE
- Do not reserve swap space for this mapping. When swap space
is reserved, one has the guarantee that it is possible to modify the
mapping. When swap space is not reserved one might get SIGSEGV upon
a write if no physical memory is available. See also the discussion of the
file /proc/sys/vm/overcommit_memory in proc(5). Before Linux
2.6, this flag had effect only for private writable mappings.
-
MAP_POPULATE
(начиная с Linux
2.5.46)
- Populate (prefault) page tables for a mapping. For a file
mapping, this causes read-ahead on the file. This will help to reduce
blocking on page faults later. The mmap() call doesn't fail if the
mapping cannot be populated (for example, due to limitations on the number
of mapped huge pages when using MAP_HUGETLB). Support for
MAP_POPULATE in conjunction with private mappings was added in
Linux 2.6.23.
-
MAP_STACK
(начиная с Linux
2.6.27)
- Allocate the mapping at an address suitable for a process
or thread stack.
- This flag is currently a no-op on Linux. However, by
employing this flag, applications can ensure that they transparently
obtain support if the flag is implemented in the future. Thus, it is used
in the glibc threading implementation to allow for the fact that some
architectures may (later) require special treatment for stack allocations.
A further reason to employ this flag is portability: MAP_STACK
exists (and has an effect) on some other systems (e.g., some of the
BSDs).
-
MAP_SYNC
(начиная с Linux
4.15)
- Данный
флаг
доступен
только с
типом
отображения
MAP_SHARED_VALIDATE;
отображения
с типом MAP_SHARED
будут
просто
игнорировать
этот флаг.
Этот флаг
поддерживается
только для
файлов
поддерживаемых
DAX (прямое
отображение
в
постоянную
память).
Для
остальных
файлов,
создание
отображения
с этим
флагом
приводит к
возврату
ошибки EOPNOTSUPP.
- Общие
файловые
отображения
с этим
флагом
представляют
гарантию
того, что
пока есть
часть
памяти
отображённая
для записи
в адресном
пространстве
процесса,
она будет
видима в
том же
файле по
тому же
смещению
даже после
падения
или
перезагрузки
системы.
Вместе с
использованием
соответствующих
инструкций
ЦП это
позволяет
пользователям
таких
отображений
эффективней
выполнять
устойчивые
изменения
данных.
-
MAP_UNINITIALIZED
(начиная с Linux
2.6.33)
- Не
очищать
анонимные
страницы.
Этот флаг
предназначен
для
повышения
производительности
на
встраиваемых
устройствах.
Он
учитывается,
только
если ядро
было
собрано с
поддержкой
параметра
CONFIG_MMAP_ALLOW_UNINITIALIZED. Так
как этот
параметр
может
привести к
нарушению
безопасности,
обычно он
устанавливается
только на
встраиваемых
устройствах
(то есть,
устройствах,
где только
один
человек
имеет
полный
контроль
над
содержимым
пользовательской
памяти).
Из флагов,
перечисленных
выше, в POSIX.1-2001 и POSIX.1-2008
определён
только
MAP_FIXED.
Однако,
большинство
систем
также
поддерживают
MAP_ANONYMOUS (или его
синоним
MAP_ANON).
Системный
вызов
munmap()
удаляет
отображение
для
указанного
адресного
диапазона
и это
приводит к
тому, что
дальнейшее
обращение
по адресам
внутри
диапазона
приводит к
генерации
неправильных
ссылок на
память.
Также для
диапазона
отображение
автоматически
удаляется
при
завершении
работы
процесса. С
другой
стороны,
закрытие
файлового
дескриптора
не
приводит к
удалению
отображения
диапазона.
Адрес
addr
должен
быть
кратен
размеру
страницы
(но
значения
length
это не
касается).
Все
страницы,
содержащие
часть
указанного
диапазона,
удаляются
из
отображения
и
последующие
ссылки на
эти
страницы
приводят к
генерации
сигнала
SIGSEGV.
Это не
ошибка,
если
указанный
диапазон
не
содержит
каких-либо
отображённых
страниц.
On success,
mmap() returns a pointer to the mapped area. On error, the
value
MAP_FAILED (that is,
(void *) -1) is
returned, and
errno is set to indicate the error.
On success,
munmap() returns 0. On failure, it returns -1, and
errno is set to indicate the error (probably to
EINVAL).
- EACCES
- Файловый
дескриптор
указывает
на не
обычный
файл. Или
было
запрошено
отображение
файла (mapping), но
fd не
открыт на
чтение. Или
был указан
флаг MAP_SHARED и
установлен
бит PROT_WRITE, но fd
не открыт в
режиме
чтения/записи
( O_RDWR). Или был
указан
флаг PROT_WRITE, но
файл
доступен
только для
дополнения.
- EAGAIN
- Файл
заблокирован,
или
блокируется
слишком
много
памяти
(смотрите
setrlimit(2)).
- EBADF
- Значение
fd не
является
правильным
файловым
дескриптором
(и MAP_ANONYMOUS не
установлен).
- EEXIST
- В flags
указан
MAP_FIXED_NOREPLACE и
диапазон,
покрываемый
addr и length,
пересекается
с
существующим
отображением.
- EINVAL
- Неправильное
значение
addr, length или offset
(например,
оно либо
слишком
велико,
либо не
выровнено
по границе
страницы).
- EINVAL
- (начиная
с Linux 2.6.12)
Значение
length равно 0.
- EINVAL
- В flags
отсутствует
MAP_PRIVATE, MAP_SHARED или
MAP_SHARED_VALIDATE.
- ENFILE
- Достигнуто
максимальное
количество
открытых
файлов в
системе.
- ENODEV
- Используемая
файловая
система
для
указанного
файла не
поддерживает
отображение
памяти.
- ENOMEM
- Больше
нет
доступной
памяти.
- ENOMEM
- Процесс
превысил
бы
ограничение
на
максимальное
количество
отображений.
Эта ошибка
также
может
возникнуть
в munmap() при
удалении
отображения
области в
середине
существующего
отображения,
так как при
этом
выполняется
удаление
отображения
двух
отображений
меньшего
размера на
любом
конце
области.
- ENOMEM
- (начиная
с Linux 4.7) Было бы
превышено
ограничение
процесса
RLIMIT_DATA,
описанное
в getrlimit(2).
- ENOMEM
- We don't like addr, because it exceeds the virtual
address space of the CPU.
- EOVERFLOW
- На
32-битной
архитектуре
вместе с
расширением
для
больших
файлов (т.е.,
используется
64-битный off_t):
количество
страниц,
используемых
для length плюс
количество
страниц,
используемых
для offset
приводит к
переполнению
unsigned long (32 бита).
- EPERM
- Аргументом
prot
запрашивается
PROT_EXEC, но
отображённая
область
принадлежит
файлу на
файловой
системе,
которая
смонтирована
с флагом no-exec.
- EPERM
- Выполнение
операции
предотвращено
опечатыванием
(file seal);
смотрите
fcntl(2).
- EPERM
- The MAP_HUGETLB flag was specified, but the caller
was not privileged (did not have the CAP_IPC_LOCK capability) and
is not a member of the sysctl_hugetlb_shm_group group; see the
description of /proc/sys/vm/sysctl_hugetlb_shm_group in
- ETXTBSY
- Был
задан флаг
MAP_DENYWRITE, но
объект,
указываемый
fd, открыт
на запись.
При
использовании
отображаемой
области
памяти
могут
возникать
следующие
сигналы:
- SIGSEGV
- Попытка
записи в
область,
отображённую
только для
чтения.
- SIGBUS
- Attempted access to a page of the buffer that lies beyond
the end of the mapped file. For an explanation of the treatment of the
bytes in the page that corresponds to the end of a mapped file that is not
a multiple of the page size, see NOTES.
Описание
терминов
данного
раздела
смотрите в
attributes(7).
Интерфейс |
Атрибут |
Значение |
mmap(), munmap() |
Безвредность
в нитях |
MT-Safe |
POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD.
В системах POSIX,
в которых
есть
вызовы
mmap(),
msync(2) и
munmap(),
значение
_POSIX_MAPPED_FILES,
определённое
в
<unistd.h>,
больше 0
(смотрите
также
sysconf(3)).
Память,
отображённая
с помощью
mmap(),
сохраняется
при
fork(2) с
теми же
атрибутами.
A file is mapped in multiples of the page size. For a file that is not a
multiple of the page size, the remaining bytes in the partial page at the end
of the mapping are zeroed when mapped, and modifications to that region are
not written out to the file. The effect of changing the size of the underlying
file of a mapping on the pages that correspond to added or removed regions of
the file is unspecified.
На
некоторых
архитектурах
(например, i386),
флаг
PROT_WRITE
подразумевает
флаг
PROT_READ.
Также от
архитектуры
зависит
подразумевает
ли
PROT_READ флаг
PROT_EXEC или нет.
Переносимые
программы
должны
всегда
устанавливать
PROT_EXEC, если они
собираются
выполнять
код,
находящийся
в
отображении.
Переносимый
способ
создания
отображения:
указать в
addr
значение 0 (NULL)
и убрать
MAP_FIXED
из
flags. В этом
случае,
система
сама
выберет
адрес для
отображения;
адрес,
выбранный
таким
образом, не
будет
будет
конфликтовать
с
существующими
отображениями
и не будет
равен 0. Если
указан
флаг
MAP_FIXED и
значение
addr
равно 0 (NULL), то
адрес
отображения
будет
равен 0 (NULL).
Некоторые
константы
flags
определены
только,
если
определён
подходящий
макрос
тестирования
свойств
(возможно,
по
умолчанию):
_DEFAULT_SOURCE в glibc 2.19 и
новее;
_BSD_SOURCE
или
_SVID_SOURCE в glibc 2.19 и
старее
(также
достаточно
использовать
_GNU_SOURCE и
требовать,
этот
макрос
логично,
так как
данные
флаги есть
только в Linux).
Соответственно,
флаги:
MAP_32BIT,
MAP_ANONYMOUS (и
синоним
MAP_ANON),
MAP_DENYWRITE,
MAP_EXECUTABLE,
MAP_FILE,
MAP_GROWSDOWN,
MAP_HUGETLB,
MAP_LOCKED,
MAP_NONBLOCK,
MAP_NORESERVE,
MAP_POPULATE и
MAP_STACK.
Приложение
может
определить
какие
страницы
отображены
в данный
момент в
буфере/страничном
кэше с
помощью
mincore(2).
Единственным
вариантом
безопасного
использования
MAP_FIXED
является
предварительное
резервирование
адресного
пространства,
указываемого
в
addr и
length,
другим
отображением;
в
остальных
случаях
использование
MAP_FIXED опасно,
так как оно
выполняет
принудительное
удаление
существующих
отображений,
что
позволяет
легко
повредить
собственное
адресное
пространство
многонитевого
процесса.
Предположим,
например,
что нить A
просматривает
/proc/<pid>/mapsв
поиске
неиспользуемого
адресного
диапазона,
который
она сможет
отобразить
используя
MAP_FIXED, но
одновременно
с этим нить B
захватывает
часть или
весь этот
же
адресный
диапазон.
Когда
после
этого нить A
запустит
mmap(MAP_FIXED), это,
фактически,
разобьёт
отображение,
созданное
нитью B. В
этом
сценарии
нити B не
нужно
создавать
отображение
явным
образом;
будет
достаточно
просто
сделать
библиотечный
вызов,
например,
dlopen(3) для
загрузки
какой-то
другой
общей
библиотеки.
Вызов
dlopen(3)
отобразит
библиотеку
в адресное
пространство
процесса.
Более того,
почти
каждый
библиотечный
вызов
можно
реализовать
так, чтобы
он
добавлял
отображения
памяти в
адресное
пространство
с помощью
этого
метода или
просто
выделяя
память.
Например,
такими
вызовами
являются
brk(2),
malloc(3),
pthread_create(3) и
библиотеки
PAM
http://www.linux-pam.org
Начиная с Linux 4.17,
в
многонитевых
программах
можно
использовать
флаг
MAP_FIXED_NOREPLACE и,
тем самым,
избежать
опасности,
описанной
выше, когда
выполняется
попытка
создать
отображение
по
фиксированному
адресу,
который не
был
зарезервирован
существующим
отображением.
У
отображённых
файлов
поле
st_atime
может
измениться
в любой
момент
между
вызовом
mmap()
и
соответствующим
удалением
отображения;
первое
обращение
к
отображённой
странице
приведёт к
обновлению
поля, если
это ещё не
было
сделано.
Поля
st_ctime и
st_mtime
у
отображённого
с помощью
флагов
PROT_WRITE и
MAP_SHARED файла
будут
обновлены
после
записи
отображённой
области и
перед
последующим
вызовом
msync(2)
с флагом
MS_SYNC
или
MS_ASYNC, если
он будет
вызван.
Для
отображений,
работающих
с
огромными
страницами,
требования
к
аргументам
mmap() и
munmap()
несколько
отличаются
от
требований
к
отображениям,
в которых
используются
страницы с
системным
размером.
Для
mmap(),
offset
должно
быть
кратно
размеру
нижележащей
огромной
страницы.
Система
автоматически
выравнивает
length до
кратного
значения
размера
нижележащей
огромной
страницы.
Для
munmap(),
addr и
length
должны
быть
кратны
размеру
нижележащей
огромной
страницы.
This page describes the interface provided by the glibc
mmap() wrapper
function. Originally, this function invoked a system call of the same name.
Since Linux 2.4, that system call has been superseded by
mmap2(2), and
nowadays the glibc
mmap() wrapper function invokes
mmap2(2) with
a suitably adjusted value for
offset.
В Linux не
гарантируется
результат
флага
MAP_NORESERVE,
описанный
выше. По
умолчанию,
любой
процесс
может быть
принудительно
завершён в
любой
момент,
если в
системе
закончилась
память.
Before Linux 2.6.7, the
MAP_POPULATE flag has effect only if
prot
is specified as
PROT_NONE.
SUSv3 specifies that
mmap() should fail if
length is 0. However,
before Linux 2.6.12,
mmap() succeeded in this case: no mapping was
created and the call returned
addr. Since Linux 2.6.12,
mmap()
fails with the error
EINVAL for this case.
В POSIX сказано,
что
система
всегда
должна
заполнять
нулями
любую
частичную
страницу у
конца
объекта и
что
система
никогда не
должна
вносить
любые
изменения
вне
пределов
объекта. В Linux,
если вы
пишите
данные в
такую
частичную
страницу
за концом
объекта, то
данные
остаются в
страничном
кэше даже
после
закрытия и
выключения
отображения
файла и
хотя
данные
никогда не
пишутся в
сам файл,
последующие
отображения
могут
увидеть
изменённое
содержимое.
В
некоторых
случаях
это можно
исправить
вызвав
msync(2)
перед
выключением
отображения;
однако это
не
работает
на
tmpfs(5)
(например,
когда
используется
интерфейс
общей
памяти POSIX,
описанный
в
shm_overview(7)).
Следующая
программа
выводит
часть
файла,
указанного
в первом
аргументе
командной
строки, в
стандартный
вывод.
Диапазон
выдаваемых
байт
задаётся
смещением
и длиной во
втором и
третьем
аргументах
командной
строки.
Программа
создаёт
отображение
требуемых
страниц
файла и
затем
использует
write(2) для
вывода
запрошенных
байт.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
int fd;
char *addr;
off_t offset, pa_offset;
size_t length;
ssize_t s;
struct stat sb;
if (argc < 3 || argc > 4) {
fprintf(stderr, "%s файл смещение [длина]\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1) /* получение размера файла */
handle_error("fstat");
offset = atoi(argv[2]);
pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
/* offset for mmap() must be page aligned */
if (offset >= sb.st_size) {
fprintf(stderr, "указанное смещение находится за концом файла\n");
exit(EXIT_FAILURE);
}
if (argc == 4) {
length = atoi(argv[3]);
if (offset + length > sb.st_size)
length = sb.st_size - offset;
/* Can't display bytes past end of file */
} else { /* Не указана длина ==> показать всё до конца файла */
length = sb.st_size - offset;
}
addr = mmap(NULL, length + offset - pa_offset, PROT_READ,
MAP_PRIVATE, fd, pa_offset);
if (addr == MAP_FAILED)
handle_error("mmap");
s = write(STDOUT_FILENO, addr + offset - pa_offset, length);
if (s != length) {
if (s == -1)
handle_error("write");
fprintf(stderr, "частичная запись");
exit(EXIT_FAILURE);
}
munmap(addr, length + offset - pa_offset);
close(fd);
exit(EXIT_SUCCESS);
}
ftruncate(2),
getpagesize(2),
memfd_create(2),
mincore(2),
mlock(2),
mmap2(2),
mprotect(2),
mremap(2),
msync(2),
remap_file_pages(2),
setrlimit(2),
shmat(2),
userfaultfd(2),
shm_open(3),
shm_overview(7)
Описание в
proc(5)
следующих
файлов:
/proc/[pid]/maps,
/proc/[pid]/map_files и
/proc/[pid]/smaps.
B.O. Gallmeister, POSIX.4, O'Reilly, pp. 128–129 and 389–391.
Русский
перевод
этой
страницы
руководства
был сделан
aereiae <
[email protected]>, Alexey <
[email protected]>, Azamat
Hackimov <
[email protected]>, Dmitriy S. Seregin
<
[email protected]>, Dmitry Bolkhovskikh <
[email protected]>,
ITriskTI <
[email protected]>, Max Is <
[email protected]>, Yuri
Kozlov <
[email protected]>, Иван
Павлов <
[email protected]>
и Малянов
Евгений
Викторович
<
[email protected]>
Этот
перевод
является
бесплатной
документацией;
прочитайте
Стандартную
общественную
лицензию GNU
версии 3
или более
позднюю,
чтобы
узнать об
условиях
авторского
права. Мы не
несем
НИКАКОЙ
ОТВЕТСТВЕННОСТИ.
Если вы
обнаружите
ошибки в
переводе
этой
страницы
руководства,
пожалуйста,
отправьте
электронное
письмо на
[email protected]