ОБЗОР
#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.
В 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 не выровнен по размеру страницы; в flags указано значение, отличное от MREMAP_MAYMOVE или MREMAP_FIXED; значение new_size равно нулю; некорректное значение new_size или new_address; новый адресный диапазон, заданный new_address и new_size, перекрывается со старым адресным диапазоном, задаваемым old_address и old_size; указан флаг MREMAP_FIXED без флага MREMAP_MAYMOVE.
- ENOMEM
- Область памяти не может быть расширена от текущего виртуального адреса и в flags не указано значение MREMAP_MAYMOVE. Или недостаточно свободной (виртуальной) памяти.
СООТВЕТСТВИЕ СТАНДАРТАМ
Данный вызов существует только в Linux и не должен использоваться в программах, которые должны быть переносимыми.ЗАМЕЧАНИЯ
До версии 2.4, в glibc не был определён флаг MREMAP_FIXED, а прототип mremap() не позволял указывать аргумент new_address.Если mremap() используется для перемещения или расширения области, заблокированной mlock(2) или эквивалентом, то вызов mremap() постарается заполнить новую область, но не завершится с ошибкой ENOMEM, если область невозможно заполнить.