summary refs log tree commit diff stats
path: root/lib/system
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system')
-rwxr-xr-xlib/system/alloc.nim25
-rwxr-xr-xlib/system/cellsets.nim22
-rwxr-xr-xlib/system/excpt.nim33
-rwxr-xr-xlib/system/gc.nim26
-rwxr-xr-xlib/system/mmdisp.nim19
-rwxr-xr-xlib/system/repr.nim4
-rwxr-xr-xlib/system/systhread.nim6
7 files changed, 66 insertions, 69 deletions
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index c385aa6fe..2280415e1 100755
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -525,22 +525,39 @@ proc isAllocatedPtr(a: TAllocator, p: pointer): bool =
 # ---------------------- interface to programs -------------------------------
 
 when not defined(useNimRtl):
-  proc alloc(size: int): pointer =
+  var heapLock: TSysLock
+  InitSysLock(HeapLock)
+
+  proc unlockedAlloc(size: int): pointer {.inline.} =
     result = rawAlloc(allocator, size+sizeof(TFreeCell))
     cast[ptr TFreeCell](result).zeroField = 1 # mark it as used
     assert(not isAllocatedPtr(allocator, result))
     result = cast[pointer](cast[TAddress](result) +% sizeof(TFreeCell))
 
-  proc alloc0(size: int): pointer =
-    result = alloc(size)
+  proc unlockedAlloc0(size: int): pointer {.inline.} =
+    result = unlockedAlloc(size)
     zeroMem(result, size)
 
-  proc dealloc(p: pointer) =
+  proc unlockedDealloc(p: pointer) {.inline.} =
     var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))
     assert(cast[ptr TFreeCell](x).zeroField == 1)
     rawDealloc(allocator, x)
     assert(not isAllocatedPtr(allocator, x))
 
+  proc alloc(size: int): pointer =
+    when hasThreadSupport: AquireSys(HeapLock)
+    result = unlockedAlloc(size)
+    when hasThreadSupport: ReleaseSys(HeapLock)
+
+  proc alloc0(size: int): pointer =
+    result = alloc(size)
+    zeroMem(result, size)
+
+  proc dealloc(p: pointer) =
+    when hasThreadSupport: AquireSys(HeapLock)
+    unlockedDealloc(p)
+    when hasThreadSupport: ReleaseSys(HeapLock)
+
   proc ptrSize(p: pointer): int =
     var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))
     result = pageAddr(x).size - sizeof(TFreeCell)
diff --git a/lib/system/cellsets.nim b/lib/system/cellsets.nim
index 0ce83864c..e262d4b77 100755
--- a/lib/system/cellsets.nim
+++ b/lib/system/cellsets.nim
@@ -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.
@@ -47,9 +47,9 @@ proc contains(s: TCellSeq, c: PCell): bool {.inline.} =
 proc add(s: var TCellSeq, c: PCell) {.inline.} =
   if s.len >= s.cap:
     s.cap = s.cap * 3 div 2
-    var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
+    var d = cast[PCellArray](unlockedAlloc(s.cap * sizeof(PCell)))
     copyMem(d, s.d, s.len * sizeof(PCell))
-    dealloc(s.d)
+    unlockedDealloc(s.d)
     s.d = d
     # XXX: realloc?
   s.d[s.len] = c
@@ -58,10 +58,10 @@ proc add(s: var TCellSeq, c: PCell) {.inline.} =
 proc init(s: var TCellSeq, cap: int = 1024) =
   s.len = 0
   s.cap = cap
-  s.d = cast[PCellArray](alloc0(cap * sizeof(PCell)))
+  s.d = cast[PCellArray](unlockedAlloc0(cap * sizeof(PCell)))
 
 proc deinit(s: var TCellSeq) = 
-  dealloc(s.d)
+  unlockedDealloc(s.d)
   s.d = nil
   s.len = 0
   s.cap = 0
@@ -70,7 +70,7 @@ const
   InitCellSetSize = 1024 # must be a power of two!
 
 proc Init(s: var TCellSet) =
-  s.data = cast[PPageDescArray](alloc0(InitCellSetSize * sizeof(PPageDesc)))
+  s.data = cast[PPageDescArray](unlockedAlloc0(InitCellSetSize * sizeof(PPageDesc)))
   s.max = InitCellSetSize-1
   s.counter = 0
   s.head = nil
@@ -79,10 +79,10 @@ proc Deinit(s: var TCellSet) =
   var it = s.head
   while it != nil:
     var n = it.next
-    dealloc(it)
+    unlockedDealloc(it)
     it = n
   s.head = nil # play it safe here
-  dealloc(s.data)
+  unlockedDealloc(s.data)
   s.data = nil
   s.counter = 0
 
@@ -110,11 +110,11 @@ proc CellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
 proc CellSetEnlarge(t: var TCellSet) =
   var oldMax = t.max
   t.max = ((t.max+1)*2)-1
-  var n = cast[PPageDescArray](alloc0((t.max + 1) * sizeof(PPageDesc)))
+  var n = cast[PPageDescArray](unlockedAlloc0((t.max + 1) * sizeof(PPageDesc)))
   for i in 0 .. oldmax:
     if t.data[i] != nil:
       CellSetRawInsert(t, n, t.data[i])
-  dealloc(t.data)
+  unlockedDealloc(t.data)
   t.data = n
 
 proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
@@ -132,7 +132,7 @@ proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
   while t.data[h] != nil: h = nextTry(h, t.max)
   assert(t.data[h] == nil)
   # the new page descriptor goes into result
-  result = cast[PPageDesc](alloc0(sizeof(TPageDesc)))
+  result = cast[PPageDesc](unlockedAlloc0(sizeof(TPageDesc)))
   result.next = t.head
   result.key = key
   t.head = result
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 01604b2c9..12069ae37 100755
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -10,6 +10,9 @@
 # Exception handling code. This is difficult because it has
 # to work if there is no more memory (but it doesn't yet!).
 
+const
+  MaxLocksPerThread = 10
+
 var
   stackTraceNewLine* = "\n" ## undocumented feature; it is replaced by ``<br>``
                             ## for CGI applications
@@ -81,11 +84,9 @@ when hasThreadSupport:
     proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {.
       importc: "pthread_setspecific", header: "<pthread.h>".}
     
-    proc specificDestroy(mem: pointer) {.noconv.} = 
-      #aquireSys(heapLock)
-      #dealloc(mem)
-      #releaseSys(heapLock)
-      #c_free(mem)
+    proc specificDestroy(mem: pointer) {.noconv.} =
+      # we really need a thread-safe 'dealloc' here:
+      dealloc(mem)
 
     proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} =
       discard pthread_key_create(addr(result), specificDestroy)
@@ -96,10 +97,12 @@ when hasThreadSupport:
       result = pthread_getspecific(s)
       
   type
-    TGlobals {.final, pure.} = object
+    TGlobals* {.final, pure.} = object
       excHandler: PSafePoint
       currException: ref E_Base
       framePtr: PFrame
+      locksLen*: int
+      locks*: array [0..MaxLocksPerThread-1, pointer]
       buf: string       # cannot be allocated on the stack!
       assertBuf: string # we need a different buffer for
                         # assert, as it raises an exception and
@@ -107,22 +110,16 @@ when hasThreadSupport:
       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
+    PGlobals* = ptr TGlobals
   
   # it's more efficient to not use a global variable for the thread storage 
   # slot, but to rely on the implementation to assign slot 0 for us... ;-)
-  var globalsSlot = ThreadVarAlloc()
-  #const globalsSlot = TThreadVarSlot(0)
-  #assert checkSlot.int == globalsSlot.int
-
-  proc AtomicAlloc0(size: int): pointer =
-    #AquireSys(heapLock)
-    result = c_malloc(size)
-    zeroMem(result, size)
-    #ReleaseSys(heapLock)
+  var checkSlot = ThreadVarAlloc()
+  const globalsSlot = TThreadVarSlot(0)
+  assert checkSlot.int == globalsSlot.int
 
   proc NewGlobals(): PGlobals = 
-    result = cast[PGlobals](AtomicAlloc0(sizeof(TGlobals)))
+    result = cast[PGlobals](alloc0(sizeof(TGlobals)))
     new(result.gAssertionFailed)
     result.buf = newStringOfCap(2000)
     result.assertBuf = newStringOfCap(2000)
@@ -134,7 +131,7 @@ when hasThreadSupport:
   proc SetThreadLocalStorage*(p: pointer) {.inl.} =
     ThreadVarSetValue(globalsSlot, p)
     
-  proc GetGlobals(): PGlobals {.compilerRtl, inl.} =
+  proc GetGlobals*(): PGlobals {.compilerRtl, inl.} =
     result = cast[PGlobals](ThreadVarGetValue(globalsSlot))
 
   # create for the main thread:
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 15d2df70e..ab8f19674 100755
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -61,9 +61,6 @@ type
     decStack: TCellSeq       # cells in the stack that are to decref again
     cycleRoots: TCellSet
     tempStack: TCellSeq      # temporary stack for recursion elimination
-    when hasThreadSupport:
-      cycleRootsLock: TSysLock
-      zctLock: TSysLock
     stat: TGcStat
 
 var
@@ -80,13 +77,11 @@ var
 
 proc aquire(gch: var TGcHeap) {.inline.} = 
   when hasThreadSupport:
-    aquireSys(gch.zctLock)
-    aquireSys(gch.cycleRootsLock)
+    AquireSys(HeapLock)
 
 proc release(gch: var TGcHeap) {.inline.} = 
   when hasThreadSupport:
-    releaseSys(gch.cycleRootsLock)
-    releaseSys(gch.zctLock)
+    releaseSys(HeapLock)
 
 proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
   if (c.refcount and rcZct) == 0:
@@ -205,18 +200,18 @@ proc prepareDealloc(cell: PCell) =
 proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = 
   # we MUST access gch as a global here, because this crosses DLL boundaries!
   when hasThreadSupport:
-    AquireSys(gch.cycleRootsLock)
+    AquireSys(HeapLock)
   incl(gch.cycleRoots, c)
   when hasThreadSupport:  
-    ReleaseSys(gch.cycleRootsLock)
+    ReleaseSys(HeapLock)
 
 proc rtlAddZCT(c: PCell) {.rtl, inl.} =
   # we MUST access gch as a global here, because this crosses DLL boundaries!
   when hasThreadSupport:
-    AquireSys(gch.zctLock)
+    AquireSys(HeapLock)
   addZCT(gch.zct, c)
   when hasThreadSupport:
-    ReleaseSys(gch.zctLock)
+    ReleaseSys(HeapLock)
 
 proc decRef(c: PCell) {.inline.} =
   when stressGC:
@@ -284,11 +279,7 @@ proc initGC() =
     init(gch.tempStack)
     Init(gch.cycleRoots)
     Init(gch.decStack)
-    when hasThreadSupport:
-      InitSysLock(gch.cycleRootsLock)
-      InitSysLock(gch.zctLock)
     new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
-    
 
 proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
   var d = cast[TAddress](dest)
@@ -690,10 +681,11 @@ proc unmarkStackAndRegisters(gch: var TGcHeap) =
   var d = gch.decStack.d
   for i in 0..gch.decStack.len-1:
     assert isAllocatedPtr(allocator, d[i])
-    # decRef(d[i]) inlined: cannot create a cycle
+    # decRef(d[i]) inlined: cannot create a cycle and must not aquire lock
     var c = d[i]
+    # XXX no need for an atomic dec here:
     if atomicDec(c.refcount, rcIncrement) <% rcIncrement:
-      rtlAddZCT(c)
+      addZCT(gch.zct, c)
     assert c.typ != nil
   gch.decStack.len = 0
 
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index f56bb233f..272a2c626 100755
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -97,6 +97,10 @@ when defined(boehmgc):
   proc dealloc(p: Pointer) =
     boehmDealloc(p)
 
+  proc unlockedAlloc(size: int): pointer {.inline.} = result = alloc(size)
+  proc unlockedAlloc0(size: int): pointer {.inline.} = result = alloc0(size)
+  proc unlockedDealloc(p: pointer) {.inline.} = dealloc(p)
+
   proc initGC() = 
     when defined(macosx): boehmGCinit()
   
@@ -148,21 +152,6 @@ elif defined(nogc):
   
   include "system/alloc"
 
-  when false:
-    proc alloc(size: int): pointer =
-      result = c_malloc(size)
-      if result == nil: raiseOutOfMem()
-    proc alloc0(size: int): pointer =
-      result = alloc(size)
-      zeroMem(result, size)
-    proc realloc(p: Pointer, newsize: int): pointer =
-      result = c_realloc(p, newsize)
-      if result == nil: raiseOutOfMem()
-    proc dealloc(p: Pointer) = c_free(p)
-    proc getOccupiedMem(): int = return -1
-    proc getFreeMem(): int = return -1
-    proc getTotalMem(): int = return -1
-
   proc initGC() = nil
   proc GC_disable() = nil
   proc GC_enable() = nil
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index 9464ff3d8..395adc2ca 100755
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -116,12 +116,16 @@ type
 
 when not defined(useNimRtl):
   proc initReprClosure(cl: var TReprClosure) =
+    # Important: cellsets does not lock the heap when doing allocations! We
+    # have to do it here ...
+    when hasThreadSupport and defined(heapLock): AquireSys(HeapLock)
     Init(cl.marked)
     cl.recdepth = -1      # default is to display everything!
     cl.indent = 0
 
   proc deinitReprClosure(cl: var TReprClosure) =
     Deinit(cl.marked)
+    when hasThreadSupport and defined(heapLock): ReleaseSys(HeapLock)
 
   proc reprBreak(result: var string, cl: TReprClosure) =
     add result, "\n"
diff --git a/lib/system/systhread.nim b/lib/system/systhread.nim
index c497cc961..c83062942 100755
--- a/lib/system/systhread.nim
+++ b/lib/system/systhread.nim
@@ -15,6 +15,8 @@ when not SystemInclude:
   # ugly hack: this file is then included from core/threads, so we have
   # thread support:
   const hasThreadSupport = true
+  
+  include "lib/system/ansi_c"
 
 when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
   proc sync_add_and_fetch(p: var int, val: int): int {.
@@ -94,7 +96,3 @@ else:
   proc ReleaseSys(L: var TSysLock) {.
     importc: "pthread_mutex_unlock", header: "<pthread.h>".}
 
-when SystemInclude:
-  var heapLock: TSysLock
-  InitSysLock(HeapLock)
-