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:
parent
d31e32743f
commit
79a326759a
6 changed files with 87 additions and 73 deletions
|
|
@ -22,7 +22,7 @@ type
|
||||||
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
|
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
|
||||||
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx,
|
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx,
|
||||||
osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks
|
osAmiga, osAtari, osNetware, osMacos, osMacosx, osIos, osHaiku, osAndroid, osVxWorks
|
||||||
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch
|
osGenode, osJS, osNimVM, osStandalone, osNintendoSwitch, osAny
|
||||||
|
|
||||||
type
|
type
|
||||||
TInfoOSProp* = enum
|
TInfoOSProp* = enum
|
||||||
|
|
@ -177,6 +177,10 @@ const
|
||||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||||
scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".",
|
scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".",
|
||||||
props: {ospNeedsPIC, ospPosix}),
|
props: {ospNeedsPIC, ospPosix}),
|
||||||
|
(name: "Any", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||||
|
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||||
|
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||||
|
props: {}),
|
||||||
]
|
]
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -2096,7 +2096,7 @@ template sysAssert(cond: bool, msg: string) =
|
||||||
|
|
||||||
const hasAlloc = (hostOS != "standalone" or not defined(nogc)) and not defined(nimscript)
|
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"
|
include "system/cgprocs"
|
||||||
when notJSnotNims and hasAlloc and not defined(nimSeqsV2):
|
when notJSnotNims and hasAlloc and not defined(nimSeqsV2):
|
||||||
proc addChar(s: NimString, c: char): NimString {.compilerproc, benign.}
|
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
|
## If the handler does not raise an exception, ordinary control flow
|
||||||
## continues and the program is terminated.
|
## 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
|
type
|
||||||
PFrame* = ptr TFrame ## Represents a runtime frame of the call stack;
|
PFrame* = ptr TFrame ## Represents a runtime frame of the call stack;
|
||||||
|
|
@ -3745,7 +3750,7 @@ when not defined(JS):
|
||||||
|
|
||||||
|
|
||||||
when notJSnotNims:
|
when notJSnotNims:
|
||||||
when hostOS != "standalone":
|
when hostOS != "standalone" and hostOS != "any":
|
||||||
include "system/dyncalls"
|
include "system/dyncalls"
|
||||||
|
|
||||||
include "system/sets"
|
include "system/sets"
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
|
||||||
# interested in
|
# interested in
|
||||||
enabled = true
|
enabled = true
|
||||||
|
|
||||||
when not hasThreadSupport:
|
when hasSomeStackTrace and not hasThreadSupport:
|
||||||
var
|
var
|
||||||
tempFrames: array[0..127, PFrame] # should not be alloc'd on stack
|
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"
|
elif s[i].line == reraisedFromEnd: result.add "]]\n"
|
||||||
else: addFrameEntry(result, s[i])
|
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:
|
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) =
|
proc rawWriteStackTrace(s: var string) =
|
||||||
when defined(nimStackTraceOverride):
|
when defined(nimStackTraceOverride):
|
||||||
add(s, "Traceback (most recent call last, using override)\n")
|
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)``.
|
## The default is to write a stacktrace to ``stderr`` and then call ``quit(1)``.
|
||||||
## Unstable API.
|
## Unstable API.
|
||||||
|
|
||||||
proc reportUnhandledError(e: ref Exception) {.nodestroy.} =
|
proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
|
||||||
when hasSomeStackTrace:
|
when hasSomeStackTrace:
|
||||||
var buf = newStringOfCap(2000)
|
var buf = newStringOfCap(2000)
|
||||||
if e.trace.len == 0:
|
if e.trace.len == 0:
|
||||||
|
|
@ -400,6 +401,14 @@ proc reportUnhandledError(e: ref Exception) {.nodestroy.} =
|
||||||
else:
|
else:
|
||||||
showErrorMessage(tbuf())
|
showErrorMessage(tbuf())
|
||||||
|
|
||||||
|
proc reportUnhandledError(e: ref Exception) {.nodestroy.} =
|
||||||
|
if unhandledExceptionHook != nil:
|
||||||
|
unhandledExceptionHook(e)
|
||||||
|
when hostOS != "any":
|
||||||
|
reportUnhandledErrorAux(e)
|
||||||
|
else:
|
||||||
|
discard()
|
||||||
|
|
||||||
proc nimLeaveFinally() {.compilerRtl.} =
|
proc nimLeaveFinally() {.compilerRtl.} =
|
||||||
when defined(cpp) and not defined(noCppExceptions):
|
when defined(cpp) and not defined(noCppExceptions):
|
||||||
{.emit: "throw;".}
|
{.emit: "throw;".}
|
||||||
|
|
@ -425,14 +434,6 @@ when gotoBasedExceptions:
|
||||||
currException = nil
|
currException = nil
|
||||||
quit(1)
|
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.} =
|
proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} =
|
||||||
if localRaiseHook != nil:
|
if localRaiseHook != nil:
|
||||||
if not localRaiseHook(e): return
|
if not localRaiseHook(e): return
|
||||||
|
|
|
||||||
|
|
@ -615,7 +615,7 @@ when declared(stdout):
|
||||||
android_log_print(ANDROID_LOG_VERBOSE, "nim", s)
|
android_log_print(ANDROID_LOG_VERBOSE, "nim", s)
|
||||||
else:
|
else:
|
||||||
# flockfile deadlocks some versions of Android 5.x.x
|
# 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 flockfile(f: File) {.importc, nodecl.}
|
||||||
proc funlockfile(f: File) {.importc, nodecl.}
|
proc funlockfile(f: File) {.importc, nodecl.}
|
||||||
flockfile(stdout)
|
flockfile(stdout)
|
||||||
|
|
@ -629,7 +629,7 @@ when declared(stdout):
|
||||||
const linefeed = "\n"
|
const linefeed = "\n"
|
||||||
discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout)
|
discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout)
|
||||||
discard c_fflush(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)
|
funlockfile(stdout)
|
||||||
when defined(windows) and compileOption("threads"):
|
when defined(windows) and compileOption("threads"):
|
||||||
releaseSys echoLock
|
releaseSys echoLock
|
||||||
|
|
|
||||||
|
|
@ -354,11 +354,11 @@ elif defined(gogc):
|
||||||
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
|
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
|
||||||
proc deallocOsPages() {.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):
|
when not defined(useNimRtl):
|
||||||
proc alloc(size: Natural): pointer =
|
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()
|
if x == nil: raiseOutOfMem()
|
||||||
|
|
||||||
cast[ptr int](x)[] = size
|
cast[ptr int](x)[] = size
|
||||||
|
|
@ -371,7 +371,7 @@ elif defined(nogc) and defined(useMalloc):
|
||||||
var x = cast[pointer](cast[int](p) - sizeof(newsize))
|
var x = cast[pointer](cast[int](p) - sizeof(newsize))
|
||||||
let oldsize = cast[ptr int](x)[]
|
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()
|
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 dealloc(p: pointer) = c_free(cast[pointer](cast[int](p) - sizeof(int)))
|
||||||
|
|
||||||
proc allocShared(size: Natural): pointer =
|
proc allocShared(size: Natural): pointer =
|
||||||
result = c_malloc(size)
|
result = c_malloc(size.csize_t)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc allocShared0(size: Natural): pointer =
|
proc allocShared0(size: Natural): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
proc reallocShared(p: pointer, newsize: Natural): pointer =
|
proc reallocShared(p: pointer, newsize: Natural): pointer =
|
||||||
result = c_realloc(p, newsize)
|
result = c_realloc(p, newsize.csize_t)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc deallocShared(p: pointer) = c_free(p)
|
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_setStrategy(strategy: GC_Strategy) = discard
|
||||||
proc GC_enableMarkAndSweep() = discard
|
proc GC_enableMarkAndSweep() = discard
|
||||||
proc GC_disableMarkAndSweep() = discard
|
proc GC_disableMarkAndSweep() = discard
|
||||||
proc GC_getStatistics(): string = return ""
|
#proc GC_getStatistics(): string = return ""
|
||||||
|
|
||||||
proc getOccupiedMem(): int = discard
|
proc getOccupiedMem(): int = discard
|
||||||
proc getFreeMem(): int = discard
|
proc getFreeMem(): int = discard
|
||||||
|
|
@ -410,13 +410,6 @@ elif defined(nogc) and defined(useMalloc):
|
||||||
|
|
||||||
proc initGC() = discard
|
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 =
|
proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -295,5 +295,16 @@ elif hostOS == "standalone" or defined(StandaloneHeapSize):
|
||||||
proc osDeallocPages(p: pointer, size: int) {.inline.} =
|
proc osDeallocPages(p: pointer, size: int) {.inline.} =
|
||||||
if bumpPointer-size == cast[int](p):
|
if bumpPointer-size == cast[int](p):
|
||||||
dec bumpPointer, size
|
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:
|
else:
|
||||||
{.error: "Port memory manager to your platform".}
|
{.error: "Port memory manager to your platform".}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue