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.
This commit is contained in:
Ico Doornekamp 2020-01-15 11:06:41 +01:00 • committed by Andreas Rumpf
commit 79a326759a
6 changed files with 87 additions and 73 deletions

View file

@ -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:
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])
proc stackTraceAvailable*(): bool
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
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 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

View file

@ -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

View file

@ -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)

View file

@ -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".}