A call to mremap() expands or shrinks mapping in the region [addr,addr+old_size) to the new size new_size. The kernel can potentially move the mapping at the same time, depending on the availability of space in the process’ address space and the value of flags.
The opening[in[addr,addr+old_size)indicates that the region starts with (and includes) the low address, whereas the closing)indicates that the region stops just before (does not include) the high address. This convention is known as interval notation.
Theflags parameter can be either0orMREMAP_MAYMOVE, which specifies that the kernel is free to move the mapping, if required, in order to perform the requested resizing. A large resizing is more likely to succeed if the kernel can move the mapping.
On success, mremap() returns a pointer to the newly resized memory mapping. On failure, it returns MAP_FAILED, and sets errnoto one of the following:
EAGAIN The memory region is locked, and cannot be resized.
EFAULT Some pages in the given range are not valid pages in the process’ address space, or there was a problem remapping the given pages.
EINVAL An argument was invalid.
ENOMEM The given range cannot be expanded without moving (andMREMAP_MAYMOVEwas not given), or there is not enough free space in the process’ address space.
Libraries such as glibc often usemremap()to implement an efficientrealloc(), which is an interface for resizing a block of memory originally obtained viamalloc(). For example:
p = mremap (addr, old_size, len, MREMAP_MAYMOVE); if (p == MAP_FAILED) return NULL; return p; }
This would only work if allmalloc()allocations were unique anonymous mappings; nonetheless, it stands as a useful example of the performance gains to be had. The example assumes the programmer has written alook_up_mapping_size()function.
The GNU C library does usemmap()and family for performing some memory allocations. We will look that topic in depth in Chapter 8.