| mmap(2) | System Calls Manual | mmap(2) |
mmap, munmap - отображает файлы или устройства в памяти, или удаляет их отображение
Стандартная библиотека языка C (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) следующие флаги:
В аргументе flags задаётся будут ли изменения отображения видимы другим процессам, отображающим ту же область, и будут ли изменения перенесены в отображённый файл. Данное поведение определяется в flags одним из следующих значений:
Флаги MAP_SHARED и MAP_PRIVATE описаны в POSIX.1-2001 и POSIX.1-2008. Флаг MAP_SHARED_VALIDATE является расширением Linux.
Кроме этого в flags могут быть указаны (побитовым сложением):
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
Из флагов, перечисленных выше, в 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).
При использовании отображаемой области памяти могут возникать следующие сигналы:
Описание терминов данного раздела смотрите в attributes(7).
| Интерфейс | Атрибут | Значение |
| mmap(), munmap() | Безвредность в нитях | MT-Safe |
На некоторых архитектурах (например, 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.
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.
POSIX.1-2008.
POSIX.1-2001, 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.
Приложение может определить какие страницы отображены в данный момент в буфере/страничном кэше с помощью mincore(2).
Единственным вариантом безопасного использования MAP_FIXED является предварительное резервирование адресного пространства, указываемого в addr и length, другим отображением; в остальных случаях использование MAP_FIXED опасно, так как оно выполняет принудительное удаление существующих отображений, что позволяет легко повредить собственное адресное пространство многонитевого процесса.
For example, suppose that thread A looks through /proc/pid/maps in order to locate an unused address range that it can map using MAP_FIXED, while thread B simultaneously acquires part or all of that same address range. When thread A subsequently employs mmap(MAP_FIXED), it will effectively clobber the mapping that thread B created. In this scenario, thread B need not create a mapping directly; simply making a library call that, internally, uses dlopen(3) to load some other shared library, will suffice. The dlopen(3) call will map the library into the process's address space. Furthermore, almost any library call may be implemented in a way that adds memory mappings to the address space, either with this technique, or by simply allocating memory. Examples include brk(2), malloc(3), pthread_create(3), and the PAM libraries 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 должны быть кратны размеру нижележащей огромной страницы.
В 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 <sys/types.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 file offset [length]\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1) /* To obtain file size */
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, "offset is past end of file\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 { /* No length arg ==> display to end of file */
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, "partial write");
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)
The descriptions of the following files in proc(5): /proc/pid/maps, /proc/pid/map_files, and /proc/pid/smaps.
B.O. Gallmeister, POSIX.4, O'Reilly, стр. 128–129 и 389–391.
Русский перевод этой страницы руководства разработал(и) aereiae <aereiae@gmail.com>, Alexey <a.chepugov@gmail.com>, Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitriy S. Seregin <dseregin@59.ru>, Dmitry Bolkhovskikh <d20052005@yandex.ru>, ITriskTI <ITriskTI@gmail.com>, Max Is <ismax799@gmail.com>, Yuri Kozlov <yuray@komyakino.ru>, Иван Павлов <pavia00@gmail.com>, Малянов Евгений Викторович <maljanow@outlook.com> и Kirill Rekhov <krekhov.dev@gmail.com>
Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.
Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков.
| 15 июня 2024 г. | Справочные страницы Linux 6.9.1 |