summaryrefslogtreecommitdiff
path: root/sysdep/unix/alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep/unix/alloc.c')
-rw-r--r--sysdep/unix/alloc.c53
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