mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-03 10:24:44 +00:00
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:
committed by
Andreas Rumpf
parent
d31e32743f
commit
79a326759a
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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".}
|
||||
|
||||
Reference in New Issue
Block a user