diff options
-rw-r--r-- | changelog.md | 3 | ||||
-rw-r--r-- | doc/nimc.rst | 14 | ||||
-rw-r--r-- | lib/system/alloc.nim | 3 | ||||
-rw-r--r-- | lib/system/osalloc.nim | 31 | ||||
-rw-r--r-- | tests/arc/tarcmisc.nim | 2 |
5 files changed, 46 insertions, 7 deletions
diff --git a/changelog.md b/changelog.md index bc64e9579..d44f28b94 100644 --- a/changelog.md +++ b/changelog.md @@ -391,6 +391,9 @@ - The `gc:orc` algorithm was refined so that custom container types can participate in the cycle collection process. +- On embedded devices `malloc` can now be used instead of `mmap` via `-d:nimAllocPagesViaMalloc`. + This is only supported for `--gc:orc` or `--gc:arc`. + ## Compiler changes diff --git a/doc/nimc.rst b/doc/nimc.rst index 2b9f33cb5..070956860 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -176,7 +176,7 @@ directories (in this order; later files overwrite previous settings): ``%APPDATA%/nim/nim.cfg`` (Windows). This file can be skipped with the `--skipUserCfg`:option: command line option. -3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent +3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be skipped with the `--skipParentCfg`:option: command-line option. @@ -634,6 +634,18 @@ optimization in the compiler and linker. Check the `Cross-compilation`_ section for instructions on how to compile the program for your target. + +nimAllocPagesViaMalloc +---------------------- + +Nim's default allocator is based on TLSF, this algorithm was designed for embedded +devices. This allocator gets blocks/pages of memory via a currently undocumented +`osalloc` API which usually uses POSIX's `mmap` call. On many environments `mmap` +is not available but C's `malloc` is. You can use the `nimAllocPagesViaMalloc` +define to use `malloc` instead of `mmap`. `nimAllocPagesViaMalloc` is currently +only supported with `--gc:arc` or `--gc:orc`. (Since version 1.6) + + Nim for realtime systems ======================== diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index c598b8250..479458950 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -749,8 +749,9 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = inc(a.allocCounter) sysAssert(allocInv(a), "rawAlloc: begin") sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken") - sysAssert(requestedSize >= sizeof(FreeCell), "rawAlloc: requested size too small") var size = roundup(requestedSize, MemAlign) + sysAssert(size >= sizeof(FreeCell), "rawAlloc: requested size too small") + sysAssert(size >= requestedSize, "insufficient allocated size!") #c_fprintf(stdout, "alloc; size: %ld; %ld\n", requestedSize, size) if size <= SmallChunkSize-smallChunkOverhead(): diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index 32d3b166d..2830adb48 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -28,7 +28,30 @@ const doNotUnmap = not (defined(amd64) or defined(i386)) or defined(windows) or defined(nimAllocNoUnmap) -when defined(emscripten) and not defined(StandaloneHeapSize): +when defined(nimAllocPagesViaMalloc): + when not defined(gcArc) and not defined(gcOrc): + {.error: "-d:nimAllocPagesViaMalloc is only supported with --gc:arc or --gc:orc".} + + proc osTryAllocPages(size: int): pointer {.inline.} = + let base = c_malloc(csize_t size + PageSize - 1 + sizeof(uint32)) + if base == nil: raiseOutOfMem() + # memory layout: padding + offset (4 bytes) + user_data + # in order to deallocate: read offset at user_data - 4 bytes, + # then deallocate user_data - offset + let offset = PageSize - (cast[int](base) and (PageSize - 1)) + cast[ptr uint32](base +! (offset - sizeof(uint32)))[] = uint32(offset) + result = base +! offset + + proc osAllocPages(size: int): pointer {.inline.} = + result = osTryAllocPages(size) + if result == nil: raiseOutOfMem() + + proc osDeallocPages(p: pointer, size: int) {.inline.} = + # read offset at p - 4 bytes, then deallocate (p - offset) pointer + let offset = cast[ptr uint32](p -! sizeof(uint32))[] + c_free(p -! offset) + +elif defined(emscripten) and not defined(StandaloneHeapSize): const PROT_READ = 1 # page can be read PROT_WRITE = 2 # page can be written @@ -197,11 +220,11 @@ elif defined(posix) and not defined(StandaloneHeapSize): PROT_WRITE = 2 # page can be written when defined(netbsd) or defined(openbsd): - # OpenBSD security for setjmp/longjmp coroutines - var MAP_STACK {.importc: "MAP_STACK", header: "<sys/mman.h>".}: cint + # OpenBSD security for setjmp/longjmp coroutines + var MAP_STACK {.importc: "MAP_STACK", header: "<sys/mman.h>".}: cint else: const MAP_STACK = 0 # avoid sideeffects - + when defined(macosx) or defined(freebsd): const MAP_ANONYMOUS = 0x1000 const MAP_PRIVATE = 0x02 # Changes are private diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 5d5d8e914..7daea62c8 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -34,7 +34,7 @@ closed destroying variable: 20 destroying variable: 10 ''' - cmd: "nim c --gc:arc --deepcopy:on $file" + cmd: "nim c --gc:arc --deepcopy:on -d:nimAllocPagesViaMalloc $file" """ proc takeSink(x: sink string): bool = true |