summary refs log tree commit diff stats
path: root/lib/system
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2010-09-13 00:52:44 +0200
committerAraq <rumpf_a@web.de>2010-09-13 00:52:44 +0200
commit866572e2e4601a1248e5ac78b151dc48fb483aa4 (patch)
treef38b3574eb66ed398d176175564eeb264bd96376 /lib/system
parent030d46f21804d8dd82edf7d5d2875e8f034dd86a (diff)
downloadNim-866572e2e4601a1248e5ac78b151dc48fb483aa4.tar.gz
fixes for exception handling; added system.compileOption
Diffstat (limited to 'lib/system')
-rwxr-xr-xlib/system/excpt.nim48
-rwxr-xr-xlib/system/gc.nim45
-rwxr-xr-xlib/system/systhread.nim46
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) =
 
 
 
-