lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


There are a couple of problems with LuaJIT on FreeBSD. One of them is
FreeBSD's lack of unwind.h, which can be fixed by pointing the build at a
copy of gcc's unwind-generic.h.

The other is that FreeBSD's mmap will not allocate memory in the region
reserved for the data segment, which by default occupies the lower 32GB +
5MB of address space. LuaJIT's NaN tagging means it needs to be able to
allocate in the bottom few GB of address space.

One way to work around this problem is to set RLIMIT_DATA to a lower value
so that the data segment occupies a small segment towards the bottom of
memory.

I have attached a patch that does this. It's basically a clone-and-hack of
the MacOS X allocation code, with the mmap region start address adjusted
to give up to about 250MB of malloc() heap.

Tony.
-- 
f.anthony.n.finch  <dot@dotat.at>  http://dotat.at/
HUMBER THAMES DOVER WIGHT PORTLAND: NORTH BACKING WEST OR NORTHWEST, 5 TO 7,
DECREASING 4 OR 5, OCCASIONALLY 6 LATER IN HUMBER AND THAMES. MODERATE OR
ROUGH. RAIN THEN FAIR. GOOD.
diff --git a/src/lj_alloc.c b/src/lj_alloc.c
index b027899..81848dc 100644
--- a/src/lj_alloc.c
+++ b/src/lj_alloc.c
@@ -203,7 +203,53 @@ static LJ_AINLINE void *CALL_MMAP(size_t size)
 
 /* FreeBSD 64 bit kernel ignores mmap() hints for lower 32GB of memory. */
 /* See: grep -C15 RLIMIT_DATA /usr/src/sys/vm/vm_mmap.c */
-#error "No support for 64 bit FreeBSD"
+/* Fix this by dropping the data segment limit. */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+
+#include <err.h>
+#include <unistd.h>
+
+static int mmap_rlimit_ok;
+
+#define MMAP_REGION_START	((uintptr_t)0x10000000)
+#define MMAP_REGION_END		((uintptr_t)0x80000000)
+
+static LJ_AINLINE void *CALL_MMAP(size_t size)
+{
+  if (!mmap_rlimit_ok) {
+    struct rlimit rlim;
+    if (getrlimit(RLIMIT_DATA, &rlim) < 0) {
+      warn("getrlimit");
+      return CMFAIL;
+    }
+    uintptr_t top = (uintptr_t)sbrk(0);
+    uintptr_t lim = MMAP_REGION_START - top;
+    rlim.rlim_cur = rlim.rlim_max = lim;
+    if (setrlimit(RLIMIT_DATA, &rlim) < 0) {
+      warn("setrlimit");
+      return CMFAIL;
+    }
+    mmap_rlimit_ok = 1;
+  }
+  /* Hint for next allocation. Doesn't need to be thread-safe. */
+  static uintptr_t alloc_hint = MMAP_REGION_START;
+  int retry = 0;
+  for (;;) {
+    void *p = mmap((void *)alloc_hint, size, MMAP_PROT, MMAP_FLAGS, -1, 0);
+    if ((uintptr_t)p >= MMAP_REGION_START &&
+	(uintptr_t)p + size < MMAP_REGION_END) {
+      alloc_hint = (uintptr_t)p + size;
+      return p;
+    }
+    if (p != CMFAIL) munmap(p, size);
+    if (retry) break;
+    retry = 1;
+    alloc_hint = MMAP_REGION_START;
+  }
+  return CMFAIL;
+}
 
 #else