mremap(2)
| MREMAP(2) | Руководство программиста Linux | MREMAP(2) |
ИМЯ
mremap - изменяет отображение адреса виртуальной памяти
ОБЗОР
#define _GNU_SOURCE /* смотрите feature_test_macros(7) */ #include <sys/mman.h>
void *mremap(void *old_address, size_t old_size,
size_t new_size, int flags, ... /* void *new_address */);
ОПИСАНИЕ
Вызов mremap() увеличивает (или уменьшает) размер существующего отображения памяти, при необходимости, перемещая его (это контролируется аргументом flags и доступным виртуальным адресным пространством).
В old_address указывается старый адрес блока виртуальной памяти, который вы хотите изменить. Заметим, что old_address должен быть выровнен по границе страницы. В old_size задаётся старый размер блока виртуальной памяти. В new_size задаётся запрашиваемый размер блока виртуальной памяти после изменения. Описание необязательного пятого аргумента new_address смотрите далее в параграфе о MREMAP_FIXED.
Если значение old_size равно нулю и old_address указывает на общее отображение (смотрите mmap(2) MAP_SHARED), то mremap() создаст новое отображение тех же страниц.Размер нового отображения будет равен значению new_size, а расположение можно указать в new_address; смотрите описание MREMAP_FIXED далее. Если новое отображение запрашивается через этот метод, то также должен быть указан флаг MREMAP_MAYMOVE.
В Linux память делится на страницы. Пользовательскому процессу выделяется один или несколько непрерывных сегментов виртуальной памяти. Каждый из этих сегментов имеет одно или несколько отображений в реальных страницах памяти (в таблице страниц). У каждого виртуального сегмента памяти есть своя защита (права доступа), которые можно нарушить, если произвести попытку некорректного доступа (например, записать информацию в сегмент, который доступен только для чтения). Доступ к виртуальной памяти за пределами сегментов также приводит к ошибке сегментации.
Вызов mremap() использует схему табличных страниц Linux. mremap() изменяет отображение между виртуальными адресами и страницами памяти. Это можно использовать при реализации очень эффективной функции realloc(3).
Аргумент битовой маски flags может быть равен 0 или содержать следующие флаги:
- MREMAP_MAYMOVE
- По умолчанию, если для расширения отображения недостаточно пространства в текущем расположении, то вызов mremap() завершается с ошибкой. Если указан флаг, то, если нужно, ядру разрешается переместить отображение на новый виртуальный адрес. Если отображение перемещено, то абсолютные указатели в старом расположении отображения становятся недействительными (должно быть выполнено смещение относительно начального адреса отображения).
- MREMAP_FIXED (начиная с Linux 2.3.31)
- Этот флаг играет ту же роль, что и MAP_FIXED для mmap(2). Если указан этот флаг, то mremap() учитывает пятый аргумент void *new_address, в котором задан выровненный на страницу адрес, куда должно быть перемещено отображение. Все предыдущие отображения в адресном диапазоне, задаваемом new_address и new_size, удаляются. При указании MREMAP_FIXED также должен быть указан MREMAP_MAYMOVE.
Если сегмент памяти, указанный old_address и old_size, заблокирован (с помощью mlock(2) или подобного вызова), то эта блокировка останется при изменении/перемещении сегмента. Следовательно, количество заблокированной процессом памяти может измениться.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении mremap() возвращается указатель на новую виртуальную область памяти. При ошибке, возвращается значение MAP_FAILED (то есть (void *) -1), а errno устанавливается в соответствующее значение.
ОШИБКИ
- EAGAIN
- Вызывающий пытается расширить заблокированный сегмент памяти, но это невозможно без превышения предела ресурса RLIMIT_MEMLOCK.
- EFAULT
- «Ошибка сегментации (Segmentation fault).» Один из адресов в диапазоне от old_address до old_address+old_size является некорректным адресом виртуальной памяти для этого процесса. Также вы можете получить EFAULT даже если существующие отображения покрывают всё запрошенное адресное пространство, но имеют различные типы.
- EINVAL
- Указан недопустимый аргумент. Возможные причины:
- не выровнено значение адреса old_address;
- помимо MREMAP_MAYMOVE или MREMAP_FIXED в flags указано что-то ещё;
- значение new_size равно нулю;
- некорректное значение new_size или new_address;
- новый диапазон адресов, указанный new_address и new_size, перекрывает старый диапазон адресов, указанный old_address и old_size;
- задан MREMAP_FIXED без MREMAP_MAYMOVE;
- значение old_size равно нулю и old_address не указывает на общее отображение (но смотрите ДЕФЕКТЫ);
- значение old_size равно нулю и не указан флаг MREMAP_MAYMOVE.
- ENOMEM
- Область памяти не может быть расширена от текущего виртуального адреса и в flags не указано значение MREMAP_MAYMOVE. Или недостаточно свободной (виртуальной) памяти.
СООТВЕТСТВИЕ СТАНДАРТАМ
Данный вызов существует только в Linux и не должен использоваться в программах, которые должны быть переносимыми.
ЗАМЕЧАНИЯ
До версии 2.4, в glibc не был определён флаг MREMAP_FIXED, а прототип mremap() не позволял указывать аргумент new_address.
Если mremap() используется для перемещения или расширения области, заблокированной mlock(2) или эквивалентом, то вызов mremap() постарается заполнить новую область, но не завершится с ошибкой ENOMEM, если область невозможно заполнить.
ДЕФЕКТЫ
До Linux 4.14, если old_size равно нулю и отображение, на которое указывает old_address — частное отображение (mmap(2) MAP_PRIVATE), то вызов mremap() создавал новое частное отображение, не относящееся к первоначальному отображению. Такое поведение не предусматривалось и, вероятно, не ожидается в приложениях пользовательского пространства (так предназначение mremap() — создание нового отображения на основе первоначального). Начиная с Linux 4.14, в этом случае mremap() завершается ошибкой EINVAL.
СМОТРИТЕ ТАКЖЕ
brk(2), getpagesize(2), getrlimit(2), mlock(2), mmap(2), sbrk(2), malloc(3), realloc(3)
Описание страничной памяти в вашей любимой книге по операционным системам (например, Современные операционные системы Эндрю С. Таненбаума, Внутри Linux Рэндольфа Бентсона, Архитектура операционной системы UNIX Мориса Дж. Баха)
| 2019-03-06 | Linux |
