further steps for thread support; bootstrapping should require unzip C sources and ./build.sh
This commit is contained in:
parent
c7b3d828be
commit
67a30d8371
21 changed files with 372 additions and 421 deletions
|
|
@ -23,50 +23,3 @@ proc nimLoadLibraryError(path: string) {.compilerproc, noinline.}
|
|||
|
||||
proc setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline.}
|
||||
|
||||
when false:
|
||||
# Support for thread local storage:
|
||||
when defined(windows):
|
||||
type
|
||||
TThreadVarSlot {.compilerproc.} = distinct int32
|
||||
|
||||
proc TlsAlloc(): TThreadVarSlot {.
|
||||
importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
|
||||
proc TlsSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
|
||||
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
|
||||
proc TlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
|
||||
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
|
||||
|
||||
proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} =
|
||||
result = TlsAlloc()
|
||||
proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {.
|
||||
compilerproc, inline.} =
|
||||
TlsSetValue(s, value)
|
||||
proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.
|
||||
compilerproc, inline.} =
|
||||
result = TlsGetValue(s)
|
||||
|
||||
else:
|
||||
type
|
||||
Tpthread_key {.importc: "pthread_key_t",
|
||||
header: "<sys/types.h>".} = distinct int
|
||||
TThreadVarSlot {.compilerproc.} = Tpthread_key
|
||||
|
||||
proc pthread_getspecific(a1: Tpthread_key): pointer {.
|
||||
importc: "pthread_getspecific", header: "<pthread.h>".}
|
||||
proc pthread_key_create(a1: ptr Tpthread_key,
|
||||
destruct: proc (x: pointer) {.noconv.}): int32 {.
|
||||
importc: "pthread_key_create", header: "<pthread.h>".}
|
||||
proc pthread_key_delete(a1: Tpthread_key): int32 {.
|
||||
importc: "pthread_key_delete", header: "<pthread.h>".}
|
||||
|
||||
proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {.
|
||||
importc: "pthread_setspecific", header: "<pthread.h>".}
|
||||
|
||||
proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} =
|
||||
discard pthread_key_create(addr(result), nil)
|
||||
proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {.
|
||||
compilerproc, inline.} =
|
||||
discard pthread_setspecific(s, value)
|
||||
proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.compilerproc, inline.} =
|
||||
result = pthread_getspecific(s)
|
||||
|
||||
|
|
|
|||
|
|
@ -85,8 +85,7 @@ proc openAppend(filename: string): TFile =
|
|||
write(result, "----------------------------------------\n")
|
||||
|
||||
proc dbgRepr(p: pointer, typ: PNimType): string =
|
||||
var
|
||||
cl: TReprClosure
|
||||
var cl: TReprClosure
|
||||
initReprClosure(cl)
|
||||
cl.recDepth = maxDisplayRecDepth
|
||||
# locks for the GC turned out to be a bad idea...
|
||||
|
|
@ -139,8 +138,10 @@ proc dbgShowCurrentProc(dbgFramePointer: PFrame) =
|
|||
write(stdout, "*** endb| (procedure name not available) ***\n")
|
||||
|
||||
proc dbgShowExecutionPoint() =
|
||||
write(stdout, "*** endb| " & $framePtr.filename & "(" & $framePtr.line &
|
||||
") " & $framePtr.procname & " ***\n")
|
||||
ThreadGlobals()
|
||||
write(stdout, "*** endb| " & $(||framePtr).filename &
|
||||
"(" & $(||framePtr).line & ") " &
|
||||
$(||framePtr).procname & " ***\n")
|
||||
|
||||
when defined(windows) or defined(dos) or defined(os2):
|
||||
{.define: FileSystemCaseInsensitive.}
|
||||
|
|
@ -171,9 +172,10 @@ proc fileMatches(c, bp: cstring): bool =
|
|||
return true
|
||||
|
||||
proc dbgBreakpointReached(line: int): int =
|
||||
ThreadGlobals()
|
||||
for i in 0..dbgBPlen-1:
|
||||
if line >= dbgBP[i].low and line <= dbgBP[i].high and
|
||||
fileMatches(framePtr.filename, dbgBP[i].filename): return i
|
||||
fileMatches((||framePtr).filename, dbgBP[i].filename): return i
|
||||
return -1
|
||||
|
||||
proc scanAndAppendWord(src: string, a: var string, start: int): int =
|
||||
|
|
@ -255,6 +257,7 @@ proc hasExt(s: string): bool =
|
|||
return false
|
||||
|
||||
proc setBreakPoint(s: string, start: int) =
|
||||
ThreadGlobals()
|
||||
var dbgTemp: string
|
||||
var i = scanWord(s, dbgTemp, start)
|
||||
if i <= start:
|
||||
|
|
@ -269,7 +272,7 @@ proc setBreakPoint(s: string, start: int) =
|
|||
i = scanNumber(s, dbgBP[x].low, i)
|
||||
if dbgBP[x].low == 0:
|
||||
# set to current line:
|
||||
dbgBP[x].low = framePtr.line
|
||||
dbgBP[x].low = (||framePtr).line
|
||||
i = scanNumber(s, dbgBP[x].high, i)
|
||||
if dbgBP[x].high == 0: # set to low:
|
||||
dbgBP[x].high = dbgBP[x].low
|
||||
|
|
@ -278,7 +281,7 @@ proc setBreakPoint(s: string, start: int) =
|
|||
if not hasExt(dbgTemp): add(dbgTemp, ".nim")
|
||||
dbgBP[x].filename = dbgTemp
|
||||
else: # use current filename
|
||||
dbgBP[x].filename = $framePtr.filename
|
||||
dbgBP[x].filename = $(||framePtr).filename
|
||||
# skip whitespace:
|
||||
while s[i] in {' ', '\t'}: inc(i)
|
||||
if s[i] != '\0':
|
||||
|
|
@ -347,9 +350,10 @@ proc dbgStackFrame(s: string, start: int, currFrame: PExtendedFrame) =
|
|||
|
||||
proc CommandPrompt() =
|
||||
# if we return from this routine, user code executes again
|
||||
ThreadGlobals()
|
||||
var
|
||||
again = True
|
||||
dbgFramePtr = framePtr # for going down and up the stack
|
||||
dbgFramePtr = ||framePtr # for going down and up the stack
|
||||
dbgDown = 0 # how often we did go down
|
||||
|
||||
while again:
|
||||
|
|
@ -366,11 +370,11 @@ proc CommandPrompt() =
|
|||
again = false
|
||||
of "n", "next":
|
||||
dbgState = dbStepOver
|
||||
dbgSkipToFrame = framePtr
|
||||
dbgSkipToFrame = ||framePtr
|
||||
again = false
|
||||
of "f", "skipcurrent":
|
||||
dbgState = dbSkipCurrent
|
||||
dbgSkipToFrame = framePtr.prev
|
||||
dbgSkipToFrame = (||framePtr).prev
|
||||
again = false
|
||||
of "c", "continue":
|
||||
dbgState = dbBreakpoints
|
||||
|
|
@ -401,7 +405,7 @@ proc CommandPrompt() =
|
|||
if dbgDown <= 0:
|
||||
debugOut("[Warning] cannot go up any further ")
|
||||
else:
|
||||
dbgFramePtr = framePtr
|
||||
dbgFramePtr = ||framePtr
|
||||
for j in 0 .. dbgDown-2: # BUGFIX
|
||||
dbgFramePtr = dbgFramePtr.prev
|
||||
dec(dbgDown)
|
||||
|
|
@ -442,16 +446,17 @@ proc endbStep() =
|
|||
CommandPrompt()
|
||||
|
||||
proc checkForBreakpoint() =
|
||||
var i = dbgBreakpointReached(framePtr.line)
|
||||
ThreadGlobals()
|
||||
var i = dbgBreakpointReached((||framePtr).line)
|
||||
if i >= 0:
|
||||
write(stdout, "*** endb| reached ")
|
||||
write(stdout, dbgBP[i].name)
|
||||
write(stdout, " in ")
|
||||
write(stdout, framePtr.filename)
|
||||
write(stdout, (||framePtr).filename)
|
||||
write(stdout, "(")
|
||||
write(stdout, framePtr.line)
|
||||
write(stdout, (||framePtr).line)
|
||||
write(stdout, ") ")
|
||||
write(stdout, framePtr.procname)
|
||||
write(stdout, (||framePtr).procname)
|
||||
write(stdout, " ***\n")
|
||||
CommandPrompt()
|
||||
|
||||
|
|
@ -482,7 +487,8 @@ proc endb(line: int) {.compilerproc.} =
|
|||
# Thus, it must have as few parameters as possible to keep the
|
||||
# code size small!
|
||||
# Check if we are at an enabled breakpoint or "in the mood"
|
||||
framePtr.line = line # this is done here for smaller code size!
|
||||
ThreadGlobals()
|
||||
(||framePtr).line = line # this is done here for smaller code size!
|
||||
if dbgLineHook != nil: dbgLineHook()
|
||||
case dbgState
|
||||
of dbStepInto:
|
||||
|
|
@ -490,7 +496,7 @@ proc endb(line: int) {.compilerproc.} =
|
|||
dbgShowExecutionPoint()
|
||||
CommandPrompt()
|
||||
of dbSkipCurrent, dbStepOver: # skip current routine
|
||||
if framePtr == dbgSkipToFrame:
|
||||
if ||framePtr == dbgSkipToFrame:
|
||||
dbgShowExecutionPoint()
|
||||
CommandPrompt()
|
||||
else: # breakpoints are wanted though (I guess)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
# However, the interface has been designed to take platform differences into
|
||||
# account and been ported to all major platforms.
|
||||
|
||||
{.push stack_trace: off.}
|
||||
|
||||
const
|
||||
NilLibHandle: TLibHandle = nil
|
||||
|
||||
|
|
@ -135,3 +137,6 @@ elif defined(mac):
|
|||
|
||||
else:
|
||||
{.error: "no implementation for dyncalls".}
|
||||
|
||||
{.pop.}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
var
|
||||
stackTraceNewLine* = "\n" ## undocumented feature; it is replaced by ``<br>``
|
||||
## for CGI applications
|
||||
isMultiThreaded: bool # true when prog created at least 1 thread
|
||||
|
||||
when not defined(windows) or not defined(guiapp):
|
||||
proc writeToStdErr(msg: CString) = write(stdout, msg)
|
||||
|
|
@ -36,30 +37,139 @@ type
|
|||
TSafePoint {.compilerproc, final.} = object
|
||||
prev: PSafePoint # points to next safe point ON THE STACK
|
||||
status: int
|
||||
exc: ref E_Base # XXX only needed for bootstrapping; unused
|
||||
context: C_JmpBuf
|
||||
|
||||
#when hasThreadSupport: nil
|
||||
when hasThreadSupport:
|
||||
# Support for thread local storage:
|
||||
when defined(windows):
|
||||
type
|
||||
TThreadVarSlot {.compilerproc.} = distinct int32
|
||||
|
||||
var
|
||||
excHandler {.threadvar, compilerproc.}: PSafePoint = nil
|
||||
# list of exception handlers
|
||||
# a global variable for the root of all try blocks
|
||||
currException {.threadvar.}: ref E_Base
|
||||
proc TlsAlloc(): TThreadVarSlot {.
|
||||
importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
|
||||
proc TlsSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
|
||||
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
|
||||
proc TlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
|
||||
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
|
||||
|
||||
proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} =
|
||||
result = TlsAlloc()
|
||||
proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {.
|
||||
compilerproc, inline.} =
|
||||
TlsSetValue(s, value)
|
||||
proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.
|
||||
compilerproc, inline.} =
|
||||
result = TlsGetValue(s)
|
||||
|
||||
else:
|
||||
{.passL: "-pthread".}
|
||||
{.passC: "-pthread".}
|
||||
|
||||
type
|
||||
Tpthread_key {.importc: "pthread_key_t",
|
||||
header: "<sys/types.h>".} = distinct int
|
||||
TThreadVarSlot {.compilerproc.} = Tpthread_key
|
||||
|
||||
proc pthread_getspecific(a1: Tpthread_key): pointer {.
|
||||
importc: "pthread_getspecific", header: "<pthread.h>".}
|
||||
proc pthread_key_create(a1: ptr Tpthread_key,
|
||||
destruct: proc (x: pointer) {.noconv.}): int32 {.
|
||||
importc: "pthread_key_create", header: "<pthread.h>".}
|
||||
proc pthread_key_delete(a1: Tpthread_key): int32 {.
|
||||
importc: "pthread_key_delete", header: "<pthread.h>".}
|
||||
|
||||
proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {.
|
||||
importc: "pthread_setspecific", header: "<pthread.h>".}
|
||||
|
||||
proc specificDestroy(mem: pointer) {.noconv.} = dealloc(mem)
|
||||
|
||||
proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} =
|
||||
discard pthread_key_create(addr(result), specificDestroy)
|
||||
proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {.
|
||||
compilerproc, inline.} =
|
||||
discard pthread_setspecific(s, value)
|
||||
proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.compilerproc, inline.} =
|
||||
result = pthread_getspecific(s)
|
||||
|
||||
type
|
||||
TGlobals {.final, pure.} = object
|
||||
excHandler: PSafePoint
|
||||
currException: ref E_Base
|
||||
framePtr: PFrame
|
||||
buf: string # cannot be allocated on the stack!
|
||||
assertBuf: string # we need a different buffer for
|
||||
# assert, as it raises an exception and
|
||||
# exception handler needs the buffer too
|
||||
gAssertionFailed: ref EAssertionFailed
|
||||
tempFrames: array [0..127, PFrame] # cannot be allocated on the stack!
|
||||
data: float # compiler should add thread local variables here!
|
||||
PGlobals = ptr TGlobals
|
||||
|
||||
var globalsSlot = ThreadVarAlloc()
|
||||
proc CreateThreadLocalStorage*() {.inl.} =
|
||||
isMultiThreaded = true
|
||||
ThreadVarSetValue(globalsSlot, alloc0(sizeof(TGlobals)))
|
||||
|
||||
proc GetGlobals(): PGlobals {.compilerRtl, inl.} =
|
||||
result = cast[PGlobals](ThreadVarGetValue(globalsSlot))
|
||||
|
||||
# create for the main thread:
|
||||
ThreadVarSetValue(globalsSlot, alloc0(sizeof(TGlobals)))
|
||||
|
||||
when hasThreadSupport:
|
||||
template ThreadGlobals =
|
||||
var globals = GetGlobals()
|
||||
template `||`(varname: expr): expr = globals.varname
|
||||
|
||||
ThreadGlobals()
|
||||
else:
|
||||
template ThreadGlobals = nil # nothing
|
||||
template `||`(varname: expr): expr = varname
|
||||
|
||||
var
|
||||
framePtr {.compilerproc.}: PFrame # XXX only temporarily a compilerproc
|
||||
excHandler: PSafePoint = nil
|
||||
# list of exception handlers
|
||||
# a global variable for the root of all try blocks
|
||||
currException: ref E_Base
|
||||
|
||||
buf: string # cannot be allocated on the stack!
|
||||
assertBuf: string # we need a different buffer for
|
||||
# assert, as it raises an exception and
|
||||
# exception handler needs the buffer too
|
||||
tempFrames: array [0..127, PFrame] # cannot be allocated on the stack!
|
||||
gAssertionFailed: ref EAssertionFailed
|
||||
|
||||
proc pushFrame(s: PFrame) {.compilerRtl, inl.} =
|
||||
ThreadGlobals()
|
||||
s.prev = ||framePtr
|
||||
||framePtr = s
|
||||
|
||||
proc popFrame {.compilerRtl, inl.} =
|
||||
ThreadGlobals()
|
||||
||framePtr = (||framePtr).prev
|
||||
|
||||
proc setFrame(s: PFrame) {.compilerRtl, inl.} =
|
||||
ThreadGlobals()
|
||||
||framePtr = s
|
||||
|
||||
proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
|
||||
s.prev = excHandler
|
||||
excHandler = s
|
||||
ThreadGlobals()
|
||||
s.prev = ||excHandler
|
||||
||excHandler = s
|
||||
|
||||
proc popSafePoint {.compilerRtl, inl.} =
|
||||
excHandler = excHandler.prev
|
||||
ThreadGlobals()
|
||||
||excHandler = (||excHandler).prev
|
||||
|
||||
proc pushCurrentException(e: ref E_Base) {.compilerRtl, inl.} =
|
||||
e.parent = currException
|
||||
currException = e
|
||||
ThreadGlobals()
|
||||
e.parent = ||currException
|
||||
||currException = e
|
||||
|
||||
proc popCurrentException {.compilerRtl, inl.} =
|
||||
currException = currException.parent
|
||||
ThreadGlobals()
|
||||
||currException = (||currException).parent
|
||||
|
||||
# some platforms have native support for stack traces:
|
||||
const
|
||||
|
|
@ -80,11 +190,16 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
|
|||
proc dladdr(addr1: pointer, info: ptr TDl_info): int {.
|
||||
importc: "dladdr", header: "<dlfcn.h>".}
|
||||
|
||||
var
|
||||
tempAddresses: array [0..127, pointer] # cannot be allocated on the stack!
|
||||
tempDlInfo: TDl_info
|
||||
when not hasThreadSupport:
|
||||
var
|
||||
tempAddresses: array [0..127, pointer] # should not be alloc'd on stack
|
||||
tempDlInfo: TDl_info
|
||||
|
||||
proc auxWriteStackTraceWithBacktrace(s: var string) =
|
||||
when hasThreadSupport:
|
||||
var
|
||||
tempAddresses: array [0..127, pointer] # but better than a threadvar
|
||||
tempDlInfo: TDl_info
|
||||
# This is allowed to be expensive since it only happens during crashes
|
||||
# (but this way you don't need manual stack tracing)
|
||||
var size = backtrace(cast[ptr pointer](addr(tempAddresses)),
|
||||
|
|
@ -108,24 +223,18 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
|
|||
# Once we're past signalHandler, we're at what the user is
|
||||
# interested in
|
||||
enabled = true
|
||||
|
||||
var
|
||||
buf: string # cannot be allocated on the stack!
|
||||
assertBuf: string # we need a different buffer for
|
||||
# assert, as it raises an exception and
|
||||
# exception handler needs the buffer too
|
||||
tempFrames: array [0..127, PFrame] # cannot be allocated on the stack!
|
||||
|
||||
proc auxWriteStackTrace(f: PFrame, s: var string) =
|
||||
const
|
||||
firstCalls = 32
|
||||
ThreadGlobals()
|
||||
var
|
||||
it = f
|
||||
i = 0
|
||||
total = 0
|
||||
while it != nil and i <= high(tempFrames)-(firstCalls-1):
|
||||
while it != nil and i <= high(||tempFrames)-(firstCalls-1):
|
||||
# the (-1) is for a nil entry that marks where the '...' should occur
|
||||
tempFrames[i] = it
|
||||
(||tempFrames)[i] = it
|
||||
inc(i)
|
||||
inc(total)
|
||||
it = it.prev
|
||||
|
|
@ -136,37 +245,38 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
|
|||
for j in 1..total-i-(firstCalls-1):
|
||||
if b != nil: b = b.prev
|
||||
if total != i:
|
||||
tempFrames[i] = nil
|
||||
(||tempFrames)[i] = nil
|
||||
inc(i)
|
||||
while b != nil and i <= high(tempFrames):
|
||||
tempFrames[i] = b
|
||||
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:
|
||||
if (||tempFrames)[j] == nil:
|
||||
add(s, "(")
|
||||
add(s, $(total-i-1))
|
||||
add(s, " calls omitted) ...")
|
||||
else:
|
||||
var oldLen = s.len
|
||||
add(s, tempFrames[j].filename)
|
||||
if tempFrames[j].line > 0:
|
||||
add(s, (||tempFrames)[j].filename)
|
||||
if (||tempFrames)[j].line > 0:
|
||||
add(s, '(')
|
||||
add(s, $tempFrames[j].line)
|
||||
add(s, $(||tempFrames)[j].line)
|
||||
add(s, ')')
|
||||
for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
|
||||
add(s, tempFrames[j].procname)
|
||||
add(s, (||tempFrames)[j].procname)
|
||||
add(s, stackTraceNewLine)
|
||||
|
||||
proc rawWriteStackTrace(s: var string) =
|
||||
when nimrodStackTrace:
|
||||
if framePtr == nil:
|
||||
ThreadGlobals()
|
||||
if ||framePtr == nil:
|
||||
add(s, "No stack traceback available")
|
||||
add(s, stackTraceNewLine)
|
||||
else:
|
||||
add(s, "Traceback (most recent call last)")
|
||||
add(s, stackTraceNewLine)
|
||||
auxWriteStackTrace(framePtr, s)
|
||||
auxWriteStackTrace(||framePtr, s)
|
||||
elif defined(nativeStackTrace) and nativeStackTraceSupported:
|
||||
add(s, "Traceback from system (most recent call last)")
|
||||
add(s, stackTraceNewLine)
|
||||
|
|
@ -184,53 +294,53 @@ proc quitOrDebug() {.inline.} =
|
|||
proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
|
||||
GC_disable() # a bad thing is an error in the GC while raising an exception
|
||||
e.name = ename
|
||||
if excHandler != nil:
|
||||
ThreadGlobals()
|
||||
if ||excHandler != nil:
|
||||
pushCurrentException(e)
|
||||
c_longjmp(excHandler.context, 1)
|
||||
c_longjmp((||excHandler).context, 1)
|
||||
else:
|
||||
if not isNil(buf):
|
||||
setLen(buf, 0)
|
||||
rawWriteStackTrace(buf)
|
||||
if not isNil(||buf):
|
||||
setLen(||buf, 0)
|
||||
rawWriteStackTrace(||buf)
|
||||
if e.msg != nil and e.msg[0] != '\0':
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
add(buf, $e.msg)
|
||||
add(||buf, "Error: unhandled exception: ")
|
||||
add(||buf, $e.msg)
|
||||
else:
|
||||
add(buf, "Error: unhandled exception")
|
||||
add(buf, " [")
|
||||
add(buf, $ename)
|
||||
add(buf, "]\n")
|
||||
writeToStdErr(buf)
|
||||
add(||buf, "Error: unhandled exception")
|
||||
add(||buf, " [")
|
||||
add(||buf, $ename)
|
||||
add(||buf, "]\n")
|
||||
writeToStdErr(||buf)
|
||||
else:
|
||||
writeToStdErr(ename)
|
||||
quitOrDebug()
|
||||
GC_enable()
|
||||
|
||||
proc reraiseException() {.compilerRtl.} =
|
||||
if currException == nil:
|
||||
ThreadGlobals()
|
||||
if ||currException == nil:
|
||||
raise newException(ENoExceptionToReraise, "no exception to reraise")
|
||||
else:
|
||||
raiseException(currException, currException.name)
|
||||
|
||||
var
|
||||
gAssertionFailed: ref EAssertionFailed
|
||||
raiseException(||currException, (||currException).name)
|
||||
|
||||
proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} =
|
||||
if not cond:
|
||||
ThreadGlobals()
|
||||
#c_fprintf(c_stdout, "Assertion failure: file %s line %ld\n", file, line)
|
||||
#quit(1)
|
||||
GC_disable() # BUGFIX: `$` allocates a new string object!
|
||||
if not isNil(assertBuf):
|
||||
if not isNil(||assertBuf):
|
||||
# BUGFIX: when debugging the GC, assertBuf may be nil
|
||||
setLen(assertBuf, 0)
|
||||
add(assertBuf, "[Assertion failure] file: ")
|
||||
add(assertBuf, file)
|
||||
add(assertBuf, " line: ")
|
||||
add(assertBuf, $line)
|
||||
add(assertBuf, "\n")
|
||||
gAssertionFailed.msg = assertBuf
|
||||
setLen(||assertBuf, 0)
|
||||
add(||assertBuf, "[Assertion failure] file: ")
|
||||
add(||assertBuf, file)
|
||||
add(||assertBuf, " line: ")
|
||||
add(||assertBuf, $line)
|
||||
add(||assertBuf, "\n")
|
||||
(||gAssertionFailed).msg = ||assertBuf
|
||||
GC_enable()
|
||||
if gAssertionFailed != nil:
|
||||
raise gAssertionFailed
|
||||
if ||gAssertionFailed != nil:
|
||||
raise ||gAssertionFailed
|
||||
else:
|
||||
c_fprintf(c_stdout, "Assertion failure: file %s line %ld\n", file, line)
|
||||
quit(1)
|
||||
|
|
@ -245,23 +355,24 @@ var
|
|||
|
||||
proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
|
||||
# print stack trace and quit
|
||||
ThreadGlobals()
|
||||
var s = sig
|
||||
GC_disable()
|
||||
setLen(buf, 0)
|
||||
rawWriteStackTrace(buf)
|
||||
setLen(||buf, 0)
|
||||
rawWriteStackTrace(||buf)
|
||||
|
||||
if s == SIGINT: add(buf, "SIGINT: Interrupted by Ctrl-C.\n")
|
||||
if s == SIGINT: add(||buf, "SIGINT: Interrupted by Ctrl-C.\n")
|
||||
elif s == SIGSEGV:
|
||||
add(buf, "SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")
|
||||
add(||buf, "SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")
|
||||
elif s == SIGABRT:
|
||||
if dbgAborting: return # the debugger wants to abort
|
||||
add(buf, "SIGABRT: Abnormal termination.\n")
|
||||
elif s == SIGFPE: add(buf, "SIGFPE: Arithmetic error.\n")
|
||||
elif s == SIGILL: add(buf, "SIGILL: Illegal operation.\n")
|
||||
add(||buf, "SIGABRT: Abnormal termination.\n")
|
||||
elif s == SIGFPE: add(||buf, "SIGFPE: Arithmetic error.\n")
|
||||
elif s == SIGILL: add(||buf, "SIGILL: Illegal operation.\n")
|
||||
elif s == SIGBUS:
|
||||
add(buf, "SIGBUS: Illegal storage access. (Attempt to read from nil?)\n")
|
||||
else: add(buf, "unknown signal\n")
|
||||
writeToStdErr(buf)
|
||||
add(||buf, "SIGBUS: Illegal storage access. (Attempt to read from nil?)\n")
|
||||
else: add(||buf, "unknown signal\n")
|
||||
writeToStdErr(||buf)
|
||||
dbgAborting = True # play safe here...
|
||||
GC_enable()
|
||||
quit(1) # always quit when SIGABRT
|
||||
|
|
@ -278,11 +389,9 @@ when not defined(noSignalHandler):
|
|||
registerSignalHandler() # call it in initialization section
|
||||
# for easier debugging of the GC, this memory is only allocated after the
|
||||
# signal handlers have been registered
|
||||
new(gAssertionFailed)
|
||||
buf = newString(2048)
|
||||
assertBuf = newString(2048)
|
||||
setLen(buf, 0)
|
||||
setLen(assertBuf, 0)
|
||||
new(||gAssertionFailed)
|
||||
||buf = newStringOfCap(2000)
|
||||
||assertBuf = newStringOfCap(2000)
|
||||
|
||||
proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} =
|
||||
raise newException(EOutOfRange, "value " & $val & " out of range")
|
||||
|
|
|
|||
|
|
@ -391,7 +391,7 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
|||
assert((cast[TAddress](res) and (MemAlign-1)) == 0)
|
||||
# now it is buffered in the ZCT
|
||||
res.typ = typ
|
||||
when debugGC:
|
||||
when debugGC and not hasThreadSupport:
|
||||
if framePtr != nil and framePtr.prev != nil:
|
||||
res.filename = framePtr.prev.filename
|
||||
res.line = framePtr.prev.line
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2009 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
|
|||
|
|
@ -23,9 +23,6 @@ else:
|
|||
inc(p, val)
|
||||
result = p
|
||||
|
||||
var
|
||||
isMultiThreaded: bool # true when prog created at least 1 thread
|
||||
|
||||
proc atomicInc(memLoc: var int, x: int): int =
|
||||
when hasThreadSupport:
|
||||
result = sync_add_and_fetch(memLoc, x)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue