6cd3771378
We can also quite simply allocate bigger blocks. Anyway, we need these blocks to be aligned to their size which needs one mmap() two times bigger and then two munmap()s returning the unaligned parts. The user can specify -B <N> on startup when <N> is the exponent of 2, setting the block size to 2^N. On most systems, N is 12, anyway if you know that your configuration is going to eat gigabytes of RAM, you are almost forced to raise your block size as you may easily get into memory fragmentation issues or you have to raise your maximum mapping count, e.g. "sysctl vm.max_map_count=(number)".
98 lines
1.8 KiB
C
98 lines
1.8 KiB
C
/*
|
|
* BIRD Internet Routing Daemon -- Raw allocation
|
|
*
|
|
* (c) 2020 Maria Matejka <mq@ucw.cz>
|
|
*
|
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
|
*/
|
|
|
|
#include "nest/bird.h"
|
|
#include "lib/resource.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef HAVE_MMAP
|
|
#include <sys/mman.h>
|
|
#endif
|
|
|
|
long page_size = 0;
|
|
_Bool alloc_multipage = 0;
|
|
|
|
#ifdef HAVE_MMAP
|
|
static _Bool use_fake = 0;
|
|
#else
|
|
static _Bool use_fake = 1;
|
|
#endif
|
|
|
|
void resource_sys_init(void)
|
|
{
|
|
#ifdef HAVE_MMAP
|
|
if (!(page_size = sysconf(_SC_PAGESIZE)))
|
|
die("System page size must be non-zero");
|
|
|
|
if ((u64_popcount(page_size) > 1) || (page_size > 16384))
|
|
{
|
|
#endif
|
|
/* Too big or strange page, use the aligned allocator instead */
|
|
page_size = 4096;
|
|
use_fake = 1;
|
|
}
|
|
}
|
|
|
|
void *
|
|
alloc_sys_page(void)
|
|
{
|
|
#ifdef HAVE_MMAP
|
|
if (!use_fake)
|
|
{
|
|
if (alloc_multipage)
|
|
{
|
|
void *big = mmap(NULL, page_size * 2, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
if (big == MAP_FAILED)
|
|
bug("mmap(%lu) failed: %m", page_size);
|
|
|
|
uintptr_t offset = ((uintptr_t) big) % page_size;
|
|
if (offset)
|
|
{
|
|
void *ret = big + page_size - offset;
|
|
munmap(big, page_size - offset);
|
|
munmap(ret + page_size, offset);
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
munmap(big + page_size, page_size);
|
|
return big;
|
|
}
|
|
}
|
|
|
|
void *ret = mmap(NULL, page_size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
if (ret == MAP_FAILED)
|
|
bug("mmap(%lu) failed: %m", page_size);
|
|
|
|
return ret;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
void *ret = aligned_alloc(page_size, page_size);
|
|
if (!ret)
|
|
bug("aligned_alloc(%lu) failed", page_size);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
void
|
|
free_sys_page(void *ptr)
|
|
{
|
|
#ifdef HAVE_MMAP
|
|
if (!use_fake)
|
|
{
|
|
if (munmap(ptr, page_size) < 0)
|
|
bug("munmap(%p) failed: %m", ptr);
|
|
}
|
|
else
|
|
#endif
|
|
free(ptr);
|
|
}
|