From 79a326759a5fb49bed60163e48e8e17f3c1ee3a3 Mon Sep 17 00:00:00 2001 From: Ico Doornekamp Date: Wed, 15 Jan 2020 11:06:41 +0100 Subject: [PATCH] Added 'ansic' os support for minimal (embedded) targets (#13088) * os:any implementation * os:asny: omit flock/funlock calls in echoBinSafe * Disabled default "unhandled expection" reporting for `--os:any` to reduce code size. Added unhandledExceptionHook instead which can be used to get a notification from Nim and handle it from the application. --- compiler/platform.nim | 6 ++- lib/system.nim | 9 +++- lib/system/excpt.nim | 107 +++++++++++++++++++++-------------------- lib/system/io.nim | 4 +- lib/system/mmdisp.nim | 19 +++----- lib/system/osalloc.nim | 11 +++++ 6 files changed, 85 insertions(+), 71 deletions(-) diff --git a/compiler/platform.nim b/compiler/platform.nim index c5d1ac6f3fec..4bac7c5a15e5 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -22,7 +22,7 @@ type osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris, osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx, osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks - osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch + osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osAny type TInfoOSProp* = enum @@ -177,6 +177,10 @@ const objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".", props: {ospNeedsPIC, ospPosix}), + (name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", + objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", + scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", + props: {}), ] type diff --git a/lib/system.nim b/lib/system.nim index 4300699771c0..1fd7a81a316f 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2096,7 +2096,7 @@ template sysAssert(cond: bool, msg: string) = const hasAlloc = (hostOS != "standalone" or not defined(nogc)) and not defined(nimscript) -when notJSnotNims and hostOS != "standalone": +when notJSnotNims and hostOS != "standalone" and hostOS != "any": include "system/cgprocs" when notJSnotNims and hasAlloc and not defined(nimSeqsV2): proc addChar(s: NimString, c: char): NimString {.compilerproc, benign.} @@ -3395,6 +3395,11 @@ var ## ## If the handler does not raise an exception, ordinary control flow ## continues and the program is terminated. + unhandledExceptionHook*: proc (e: ref Exception) {.nimcall, tags: [], benign, raises: [].} + ## Set this variable to provide a procedure that should be called + ## in case of an `unhandle exception` event. The standard handler + ## writes an error message and terminates the program, except when + ## using `--os:any` type PFrame* = ptr TFrame ## Represents a runtime frame of the call stack; @@ -3745,7 +3750,7 @@ when not defined(JS): when notJSnotNims: - when hostOS != "standalone": + when hostOS != "standalone" and hostOS != "any": include "system/dyncalls" include "system/sets" diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 931f3f64019a..91cf9aa3eb3f 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -210,7 +210,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported: # interested in enabled = true -when not hasThreadSupport: +when hasSomeStackTrace and not hasThreadSupport: var tempFrames: array[0..127, PFrame] # should not be alloc'd on stack @@ -261,52 +261,53 @@ proc `$`(s: seq[StackTraceEntry]): string = elif s[i].line == reraisedFromEnd: result.add "]]\n" else: addFrameEntry(result, s[i]) -proc auxWriteStackTrace(f: PFrame, s: var string) = - when hasThreadSupport: +when hasSomeStackTrace: + + proc auxWriteStackTrace(f: PFrame, s: var string) = + when hasThreadSupport: + var + tempFrames: array[0..127, PFrame] # but better than a threadvar + const + firstCalls = 32 var - tempFrames: array[0..127, PFrame] # but better than a threadvar - const - firstCalls = 32 - var - it = f - i = 0 - total = 0 - # setup long head: - while it != nil and i <= high(tempFrames)-firstCalls: - tempFrames[i] = it - inc(i) - inc(total) - it = it.prev - # go up the stack to count 'total': - var b = it - while it != nil: - inc(total) - it = it.prev - var skipped = 0 - if total > len(tempFrames): - # skip N - skipped = total-i-firstCalls+1 - for j in 1..skipped: - if b != nil: b = b.prev - # create '...' entry: - tempFrames[i] = nil - inc(i) - # setup short tail: - while b != nil and i <= high(tempFrames): - tempFrames[i] = b - inc(i) - b = b.prev - for j in countdown(i-1, 0): - if tempFrames[j] == nil: - add(s, "(") - add(s, $skipped) - add(s, " calls omitted) ...\n") - else: - addFrameEntry(s, tempFrames[j]) + it = f + i = 0 + total = 0 + # setup long head: + while it != nil and i <= high(tempFrames)-firstCalls: + tempFrames[i] = it + inc(i) + inc(total) + it = it.prev + # go up the stack to count 'total': + var b = it + while it != nil: + inc(total) + it = it.prev + var skipped = 0 + if total > len(tempFrames): + # skip N + skipped = total-i-firstCalls+1 + for j in 1..skipped: + if b != nil: b = b.prev + # create '...' entry: + tempFrames[i] = nil + inc(i) + # setup short tail: + while b != nil and i <= high(tempFrames): + tempFrames[i] = b + inc(i) + b = b.prev + for j in countdown(i-1, 0): + if tempFrames[j] == nil: + add(s, "(") + add(s, $skipped) + add(s, " calls omitted) ...\n") + else: + addFrameEntry(s, tempFrames[j]) -proc stackTraceAvailable*(): bool + proc stackTraceAvailable*(): bool -when hasSomeStackTrace: proc rawWriteStackTrace(s: var string) = when defined(nimStackTraceOverride): add(s, "Traceback (most recent call last, using override)\n") @@ -351,7 +352,7 @@ var onUnhandledException*: (proc (errorMsg: string) {. ## The default is to write a stacktrace to ``stderr`` and then call ``quit(1)``. ## Unstable API. -proc reportUnhandledError(e: ref Exception) {.nodestroy.} = +proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = when hasSomeStackTrace: var buf = newStringOfCap(2000) if e.trace.len == 0: @@ -400,6 +401,14 @@ proc reportUnhandledError(e: ref Exception) {.nodestroy.} = else: showErrorMessage(tbuf()) +proc reportUnhandledError(e: ref Exception) {.nodestroy.} = + if unhandledExceptionHook != nil: + unhandledExceptionHook(e) + when hostOS != "any": + reportUnhandledErrorAux(e) + else: + discard() + proc nimLeaveFinally() {.compilerRtl.} = when defined(cpp) and not defined(noCppExceptions): {.emit: "throw;".} @@ -425,14 +434,6 @@ when gotoBasedExceptions: currException = nil quit(1) - addQuitProc(proc () {.noconv.} = - if currException != nil: - reportUnhandledError(currException) - # emulate: ``programResult = 1`` via abort() and a nop signal handler. - c_signal(SIGABRT, (proc (sign: cint) {.noconv, benign.} = discard)) - c_abort() - ) - proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} = if localRaiseHook != nil: if not localRaiseHook(e): return diff --git a/lib/system/io.nim b/lib/system/io.nim index a8f690054f73..41716f9afe53 100644 --- a/lib/system/io.nim +++ b/lib/system/io.nim @@ -615,7 +615,7 @@ when declared(stdout): android_log_print(ANDROID_LOG_VERBOSE, "nim", s) else: # flockfile deadlocks some versions of Android 5.x.x - when not defined(windows) and not defined(android) and not defined(nintendoswitch): + when not defined(windows) and not defined(android) and not defined(nintendoswitch) and hostOS != "any": proc flockfile(f: File) {.importc, nodecl.} proc funlockfile(f: File) {.importc, nodecl.} flockfile(stdout) @@ -629,7 +629,7 @@ when declared(stdout): const linefeed = "\n" discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout) discard c_fflush(stdout) - when not defined(windows) and not defined(android) and not defined(nintendoswitch): + when not defined(windows) and not defined(android) and not defined(nintendoswitch) and hostOS != "any": funlockfile(stdout) when defined(windows) and compileOption("threads"): releaseSys echoLock diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 8bc8fe28abef..faa7813fb497 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -354,11 +354,11 @@ elif defined(gogc): proc deallocOsPages(r: var MemRegion) {.inline.} = discard proc deallocOsPages() {.inline.} = discard -elif defined(nogc) and defined(useMalloc): +elif (defined(nogc) or defined(gcDestructors)) and defined(useMalloc): when not defined(useNimRtl): proc alloc(size: Natural): pointer = - var x = c_malloc(size + sizeof(size)) + var x = c_malloc (size + sizeof(size)).csize_t if x == nil: raiseOutOfMem() cast[ptr int](x)[] = size @@ -371,7 +371,7 @@ elif defined(nogc) and defined(useMalloc): var x = cast[pointer](cast[int](p) - sizeof(newsize)) let oldsize = cast[ptr int](x)[] - x = c_realloc(x, newsize + sizeof(newsize)) + x = c_realloc(x, (newsize + sizeof(newsize)).csize_t) if x == nil: raiseOutOfMem() @@ -384,13 +384,13 @@ elif defined(nogc) and defined(useMalloc): proc dealloc(p: pointer) = c_free(cast[pointer](cast[int](p) - sizeof(int))) proc allocShared(size: Natural): pointer = - result = c_malloc(size) + result = c_malloc(size.csize_t) if result == nil: raiseOutOfMem() proc allocShared0(size: Natural): pointer = result = alloc(size) zeroMem(result, size) proc reallocShared(p: pointer, newsize: Natural): pointer = - result = c_realloc(p, newsize) + result = c_realloc(p, newsize.csize_t) if result == nil: raiseOutOfMem() proc deallocShared(p: pointer) = c_free(p) @@ -400,7 +400,7 @@ elif defined(nogc) and defined(useMalloc): proc GC_setStrategy(strategy: GC_Strategy) = discard proc GC_enableMarkAndSweep() = discard proc GC_disableMarkAndSweep() = discard - proc GC_getStatistics(): string = return "" + #proc GC_getStatistics(): string = return "" proc getOccupiedMem(): int = discard proc getFreeMem(): int = discard @@ -410,13 +410,6 @@ elif defined(nogc) and defined(useMalloc): proc initGC() = discard - proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = - result = alloc0(size) - proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = - result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize)) - cast[PGenericSeq](result).len = len - cast[PGenericSeq](result).reserved = len - proc newObjNoInit(typ: PNimType, size: int): pointer = result = alloc(size) diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index 85c32e67603c..28a426e65432 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -295,5 +295,16 @@ elif hostOS == "standalone" or defined(StandaloneHeapSize): proc osDeallocPages(p: pointer, size: int) {.inline.} = if bumpPointer-size == cast[int](p): dec bumpPointer, size + +elif hostOS == "any": + proc osAllocPages(size: int): pointer {.inline.} = + result = c_malloc(size.csize_t) + + proc osTryAllocPages(size: int): pointer {.inline.} = + result = c_malloc(size.csize_t) + + proc osDeallocPages(p: pointer, size: int) {.inline.} = + c_free(p) + else: {.error: "Port memory manager to your platform".}