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
parent d31e32743f
commit 79a326759a
6 changed files with 87 additions and 73 deletions

View File

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

View File

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

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