summaryrefslogtreecommitdiff
path: root/sysdep/unix
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep/unix')
-rw-r--r--sysdep/unix/alloc.c64
-rw-r--r--sysdep/unix/io.c4
2 files changed, 61 insertions, 7 deletions
diff --git a/sysdep/unix/alloc.c b/sysdep/unix/alloc.c
index c525f713..0e944d57 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,20 +59,30 @@ 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);
if (ret == MAP_FAILED)
- bug("mmap(%lu) failed: %m", page_size);
+ bug("mmap(%lu) failed: %m", (long unsigned int) 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 *ptr = NULL;
+ int err = posix_memalign(&ptr, page_size, page_size);
+ if (err || !ptr)
+ bug("posix_memalign(%lu) failed", (long unsigned int) page_size);
+ return ptr;
}
}
@@ -71,10 +92,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
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index 3d67d0a7..4fd77453 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -1436,6 +1436,10 @@ sk_open(sock *s)
if (sk_set_high_port(s) < 0)
log(L_WARN "Socket error: %s%#m", s->err);
+ if (s->flags & SKF_FREEBIND)
+ if (sk_set_freebind(s) < 0)
+ log(L_WARN "Socket error: %s%#m", s->err);
+
sockaddr_fill(&sa, s->af, bind_addr, s->iface, bind_port);
if (bind(fd, &sa.sa, SA_LEN(sa)) < 0)
ERR2("bind");