diff options
Diffstat (limited to 'sysdep')
-rw-r--r-- | sysdep/unix/alloc.c | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/sysdep/unix/alloc.c b/sysdep/unix/alloc.c index c525f713..5dd70c99 100644 --- a/sysdep/unix/alloc.c +++ b/sysdep/unix/alloc.c @@ -8,6 +8,8 @@ #include "nest/bird.h" #include "lib/resource.h" +#include "lib/lists.h" +#include "lib/event.h" #include <stdlib.h> #include <unistd.h> @@ -17,8 +19,17 @@ #endif #ifdef HAVE_MMAP +#define KEEP_PAGES 512 + static u64 page_size = 0; static _Bool use_fake = 0; + +uint pages_kept = 0; +static list pages_list; + +static void cleanup_pages(void *data); +static event page_cleanup_event = { .hook = cleanup_pages }; + #else static const u64 page_size = 4096; /* Fake page size */ #endif @@ -48,6 +59,15 @@ void * alloc_page(void) { #ifdef HAVE_MMAP + if (pages_kept) + { + node *page = TAIL(pages_list); + rem_node(page); + pages_kept--; + memset(page, 0, get_page_size()); + return page; + } + if (!use_fake) { void *ret = mmap(NULL, get_page_size(), PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); @@ -71,10 +91,39 @@ free_page(void *ptr) #ifdef HAVE_MMAP if (!use_fake) { - if (munmap(ptr, get_page_size()) < 0) - bug("munmap(%p) failed: %m", ptr); + if (!pages_kept) + init_list(&pages_list); + + memset(ptr, 0, sizeof(node)); + add_tail(&pages_list, ptr); + + if (++pages_kept > KEEP_PAGES) + ev_schedule(&page_cleanup_event); } else #endif free(ptr); } + +#ifdef HAVE_MMAP +static void +cleanup_pages(void *data UNUSED) +{ + for (uint seen = 0; (pages_kept > KEEP_PAGES) && (seen < KEEP_PAGES); seen++) + { + void *ptr = HEAD(pages_list); + rem_node(ptr); + if (munmap(ptr, get_page_size()) == 0) + pages_kept--; +#ifdef ENOMEM + else if (errno == ENOMEM) + add_tail(&pages_list, ptr); +#endif + else + bug("munmap(%p) failed: %m", ptr); + } + + if (pages_kept > KEEP_PAGES) + ev_schedule(&page_cleanup_event); +} +#endif |