Using mmap() for Advanced File I/O - Resizing a Mapping (
Page 2 of 5 )
Linux provides the mremap() system call for expanding or shrinking the size of a given mapping. This function is Linux-specific:
#define _GNU_SOURCE
#include <unistd.h
>
#include <sys/mman.h>
void * mremap (void *addr, size_t old_size,
size_t new_size, unsigned long flags);
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.
The
flags
parameter can be either
0
or
MREMAP_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 errno
to 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
(and
MREMAP_MAYMOVE
was not given), or there is
not enough free space in the process’ address space.
Libraries such as glibc often use
mremap()
to implement an efficient
realloc()
, which is an interface for resizing a block of memory originally obtained via
malloc()
. For example:
void * realloc (void *addr, size_t len)
{
size_t old_size = look_up_mapping_size (addr);
void *p;
p = mremap (addr, old_size, len, MREMAP_MAYMOVE)
;
if (p == MAP_FAILED)
return NULL;
return p;
}
This would only work if all
malloc()
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 a
look_up_mapping_size()
function.
The GNU C library does use
mmap()
and family for performing some memory alloca
tions. We will look that topic in depth in Chapter 8.