diff options
author | Araq <rumpf_a@web.de> | 2010-09-13 00:52:44 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2010-09-13 00:52:44 +0200 |
commit | 866572e2e4601a1248e5ac78b151dc48fb483aa4 (patch) | |
tree | f38b3574eb66ed398d176175564eeb264bd96376 /lib/system | |
parent | 030d46f21804d8dd82edf7d5d2875e8f034dd86a (diff) | |
download | Nim-866572e2e4601a1248e5ac78b151dc48fb483aa4.tar.gz |
fixes for exception handling; added system.compileOption
Diffstat (limited to 'lib/system')
-rwxr-xr-x | lib/system/excpt.nim | 48 | ||||
-rwxr-xr-x | lib/system/gc.nim | 45 | ||||
-rwxr-xr-x | lib/system/systhread.nim | 46 |
3 files changed, 110 insertions, 29 deletions
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index d8bdf2a9f..c473c42f0 100755 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -20,9 +20,6 @@ else: proc writeToStdErr(msg: CString) = discard MessageBoxA(0, msg, nil, 0) -proc raiseException(e: ref E_Base, ename: CString) {.compilerproc.} -proc reraiseException() {.compilerproc.} - proc registerSignalHandler() {.compilerproc.} proc chckIndx(i, a, b: int): int {.inline, compilerproc.} @@ -34,20 +31,29 @@ type PSafePoint = ptr TSafePoint TSafePoint {.compilerproc, final.} = object prev: PSafePoint # points to next safe point ON THE STACK - exc: ref E_Base status: int + exc: ref E_Base # XXX only needed for bootstrapping context: C_JmpBuf var excHandler {.compilerproc.}: PSafePoint = nil # list of exception handlers # a global variable for the root of all try blocks + currException: ref E_Base -proc reraiseException() = - if excHandler == nil: - raise newException(ENoExceptionToReraise, "no exception to reraise") - else: - c_longjmp(excHandler.context, 1) +proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = + s.prev = excHandler + excHandler = s + +proc popSafePoint {.compilerRtl, inl.} = + excHandler = excHandler.prev + +proc pushCurrentException(e: ref E_Base) {.compilerRtl, inl.} = + e.parent = currException + currException = e + +proc popCurrentException {.compilerRtl, inl.} = + currException = currException.parent type PFrame = ptr TFrame @@ -114,13 +120,17 @@ proc auxWriteStackTrace(f: PFrame, s: var string) = add(s, stackTraceNewLine) proc rawWriteStackTrace(s: var string) = - if framePtr == nil: - add(s, "No stack traceback available") - add(s, stackTraceNewLine) + when compileOption("stacktrace") or compileOption("linetrace"): + 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) else: - add(s, "Traceback (most recent call last)") + add(s, "No stack traceback available") add(s, stackTraceNewLine) - auxWriteStackTrace(framePtr, s) proc quitOrDebug() {.inline.} = when not defined(endb): @@ -128,11 +138,11 @@ proc quitOrDebug() {.inline.} = else: endbStep() # call the debugger -proc raiseException(e: ref E_Base, ename: CString) = +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: - excHandler.exc = e + pushCurrentException(e) c_longjmp(excHandler.context, 1) else: if not isNil(buf): @@ -152,6 +162,12 @@ proc raiseException(e: ref E_Base, ename: CString) = quitOrDebug() GC_enable() +proc reraiseException() {.compilerRtl.} = + if currException == nil: + raise newException(ENoExceptionToReraise, "no exception to reraise") + else: + raiseException(currException, currException.name) + var gAssertionFailed: ref EAssertionFailed diff --git a/lib/system/gc.nim b/lib/system/gc.nim index cd803d70a..0c403b4bc 100755 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -61,6 +61,8 @@ type decStack: TCellSeq # cells in the stack that are to decref again cycleRoots: TCellSet tempStack: TCellSeq # temporary stack for recursion elimination + cycleRootsLock: TSysLock + zctLock: TSysLock stat: TGcStat var @@ -68,12 +70,22 @@ var gch: TGcHeap cycleThreshold: int = InitialCycleThreshold recGcLock: int = 0 - # we use a lock to prevend the garbage collector to be triggered in a + # we use a lock to prevent the garbage collector to be triggered in a # finalizer; the collector should not call itself this way! Thus every # object allocated by a finalizer will not trigger a garbage collection. # This is wasteful but safe. This is a lock against recursive garbage # collection, not a lock for threads! +proc lock(gch: var TGcHeap) {.inline.} = + if isMultiThreaded: + Lock(gch.zctLock) + lock(gch.cycleRootsLock) + +proc unlock(gch: var TGcHeap) {.inline.} = + if isMultiThreaded: + unlock(gch.zctLock) + unlock(gch.cycleRootsLock) + proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} = if (c.refcount and rcZct) == 0: c.refcount = c.refcount and not colorMask or rcZct @@ -159,7 +171,7 @@ when traceGC: for c in elements(states[csAllocated]): inc(e) if c in states[csZctFreed]: inc(z) - elif c in states[csCycFreed]: inc(z) + elif c in states[csCycFreed]: inc(y) else: writeCell("leak", c) cfprintf(cstdout, "Allocations: %ld; ZCT freed: %ld; CYC freed: %ld\n", e, z, y) @@ -190,25 +202,28 @@ proc prepareDealloc(cell: PCell) = proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = # we MUST access gch as a global here, because this crosses DLL boundaries! + if isMultiThreaded: Lock(gch.cycleRootsLock) incl(gch.cycleRoots, c) + if isMultiThreaded: Unlock(gch.cycleRootsLock) proc rtlAddZCT(c: PCell) {.rtl, inl.} = # we MUST access gch as a global here, because this crosses DLL boundaries! + if isMultiThreaded: Lock(gch.zctLock) addZCT(gch.zct, c) + if isMultiThreaded: Unlock(gch.zctLock) proc decRef(c: PCell) {.inline.} = when stressGC: if c.refcount <% rcIncrement: writeCell("broken cell", c) assert(c.refcount >=% rcIncrement) - c.refcount = c.refcount -% rcIncrement - if c.refcount <% rcIncrement: + if atomicDec(c.refcount, rcIncrement) <% rcIncrement: rtlAddZCT(c) elif canBeCycleRoot(c): rtlAddCycleRoot(c) proc incRef(c: PCell) {.inline.} = - c.refcount = c.refcount +% rcIncrement + discard atomicInc(c.refcount, rcIncrement) if canBeCycleRoot(c): rtlAddCycleRoot(c) @@ -228,11 +243,10 @@ proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerProc, inline.} = # cycle is possible. if src != nil: var c = usrToCell(src) - c.refcount = c.refcount +% rcIncrement + discard atomicInc(c.refcount, rcIncrement) if dest^ != nil: var c = usrToCell(dest^) - c.refcount = c.refcount -% rcIncrement - if c.refcount <% rcIncrement: + if atomicDec(c.refcount, rcIncrement) <% rcIncrement: rtlAddZCT(c) dest^ = src @@ -260,6 +274,8 @@ proc initGC() = init(gch.tempStack) Init(gch.cycleRoots) Init(gch.decStack) + InitLock(gch.cycleRootsLock) + InitLock(gch.zctLock) new(gOutOfMem) # reserve space for the EOutOfMemory exception here! proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) = @@ -310,6 +326,7 @@ proc checkCollection {.inline.} = proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = # generates a new object and sets its reference counter to 0 + lock(gch) assert(typ.kind in {tyRef, tyString, tySequence}) checkCollection() var res = cast[PCell](rawAlloc(allocator, size + sizeof(TCell))) @@ -337,15 +354,18 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = break addToZCT add(gch.zct, res) when logGC: writeCell("new cell", res) - gcTrace(res, csAllocated) + gcTrace(res, csAllocated) + unlock(gch) result = cellToUsr(res) proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = + # `newObj` already uses locks, so no need for them here. result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize)) cast[PGenericSeq](result).len = len cast[PGenericSeq](result).space = len proc growObj(old: pointer, newsize: int): pointer {.rtl.} = + lock(gch) checkCollection() var ol = usrToCell(old) assert(ol.typ != nil) @@ -383,6 +403,7 @@ proc growObj(old: pointer, newsize: int): pointer {.rtl.} = else: assert(ol.typ != nil) zeroMem(ol, sizeof(TCell)) + unlock(gch) result = cellToUsr(res) # ---------------- cycle collector ------------------------------------------- @@ -632,9 +653,9 @@ proc collectCT(gch: var TGcHeap) = unmarkStackAndRegisters(gch) when not defined(useNimRtl): - proc GC_disable() = inc(recGcLock) + proc GC_disable() = discard atomicInc(recGcLock, 1) proc GC_enable() = - if recGcLock > 0: dec(recGcLock) + if recGcLock > 0: discard atomicDec(recGcLock, 1) proc GC_setStrategy(strategy: TGC_Strategy) = case strategy @@ -651,10 +672,12 @@ when not defined(useNimRtl): # set to the max value to suppress the cycle detector proc GC_fullCollect() = + lock(gch) var oldThreshold = cycleThreshold cycleThreshold = 0 # forces cycle collection collectCT(gch) cycleThreshold = oldThreshold + unlock(gch) proc GC_getStatistics(): string = GC_disable() diff --git a/lib/system/systhread.nim b/lib/system/systhread.nim index 58482ac65..583cd2a43 100755 --- a/lib/system/systhread.nim +++ b/lib/system/systhread.nim @@ -15,6 +15,10 @@ when defined(gcc) or defined(llvm_gcc): elif defined(vcc): proc sync_add_and_fetch(p: var int, val: int): int {. importc: "NimXadd", nodecl.} +else: + proc sync_add_and_fetch(p: var int, val: int): int {.inline.} = + inc(p, val) + result = p const isMultiThreaded* = true @@ -37,12 +41,51 @@ proc atomicDec(memLoc: var int, x: int): int = dec(memLoc, x) result = memLoc +when defined(Windows): + type + THandle = int + TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi + DebugInfo: pointer + LockCount: int32 + RecursionCount: int32 + OwningThread: int + LockSemaphore: int + Reserved: int32 + + proc InitLock(L: var TSysLock) {.stdcall, + dynlib: "kernel32", importc: "InitializeCriticalSection".} + proc Lock(L: var TSysLock) {.stdcall, + dynlib: "kernel32", importc: "EnterCriticalSection".} + proc Unlock(L: var TSysLock) {.stdcall, + dynlib: "kernel32", importc: "LeaveCriticalSection".} + + proc CreateThread(lpThreadAttributes: Pointer, dwStackSize: int32, + lpStartAddress: pointer, lpParameter: Pointer, + dwCreationFlags: int32, lpThreadId: var int32): THandle {. + stdcall, dynlib: "kernel32", importc: "CreateThread".} + + +else: + type + TSysLock {.importc: "pthread_mutex_t", header: "<sys/types.h>".} = int + TSysThread {.importc: "pthread_t", header: "<sys/types.h>".} = int + + proc InitLock(L: var TSysLock, attr: pointer = nil) {. + importc: "pthread_mutex_init", header: "<pthread.h>".} + proc Lock(L: var TSysLock) {. + importc: "pthread_mutex_lock", header: "<pthread.h>".} + proc Unlock(L: var TSysLock) {. + importc: "pthread_mutex_unlock", header: "<pthread.h>".} + + type TThread* {.final, pure.} = object + id: int next: ptr TThread - TThreadFunc* = proc (closure: pointer) + TThreadFunc* = proc (closure: pointer) {.cdecl.} proc createThread*(t: var TThread, fn: TThreadFunc) = + nil proc destroyThread*(t: var TThread) = @@ -50,4 +93,3 @@ proc destroyThread*(t: var TThread) = - |