summary refs log tree commit diff stats
path: root/lib/system
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-06-04 23:55:10 +0200
committerAraq <rumpf_a@web.de>2011-06-04 23:55:10 +0200
commit24ed9d560fb7a694c90dc0a378549a06600fcbd0 (patch)
treebe0f8f2b0f44387e8e2c9b75c8db0506aece9a0b /lib/system
parent5008b44467bf545287289087a13f7e53c3d242ff (diff)
downloadNim-24ed9d560fb7a694c90dc0a378549a06600fcbd0.tar.gz
threads clean up their heap
Diffstat (limited to 'lib/system')
-rwxr-xr-xlib/system/alloc.nim59
-rwxr-xr-xlib/system/excpt.nim4
-rwxr-xr-xlib/system/sysio.nim3
-rwxr-xr-xlib/system/threads.nim28
4 files changed, 67 insertions, 27 deletions
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index 0218e3baa..3273242d6 100755
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -91,7 +91,7 @@ type
     key: int             # start address at bit 0
     bits: array[0..IntsPerTrunk-1, int] # a bit vector
   
-  TTrunkBuckets = array[0..1023, PTrunk]
+  TTrunkBuckets = array[0..255, PTrunk]
   TIntSet {.final.} = object 
     data: TTrunkBuckets
   
@@ -119,8 +119,7 @@ type
     data: TAlignType     # start of usable memory
   
   TBigChunk = object of TBaseChunk # not necessarily > PageSize!
-    next: PBigChunk      # chunks of the same (or bigger) size
-    prev: PBigChunk
+    next, prev: PBigChunk    # chunks of the same (or bigger) size
     align: int
     data: TAlignType     # start of usable memory
 
@@ -148,6 +147,7 @@ type
   TLLChunk {.pure.} = object ## *low-level* chunk
     size: int                # remaining size
     acc: int                 # accumulator
+    next: PLLChunk           # next low-level chunk; only needed for dealloc
     
   TAllocator {.final, pure.} = object
     llmem: PLLChunk
@@ -172,18 +172,31 @@ proc getMaxMem(a: var TAllocator): int =
   
 proc llAlloc(a: var TAllocator, size: int): pointer =
   # *low-level* alloc for the memory managers data structures. Deallocation
-  # is never done.
+  # is done at he end of the allocator's life time.
   if a.llmem == nil or size > a.llmem.size:
-    var request = roundup(size+sizeof(TLLChunk), PageSize)
-    a.llmem = cast[PLLChunk](osAllocPages(request))
-    incCurrMem(a, request)
-    a.llmem.size = request - sizeof(TLLChunk)
+    # the requested size is ``roundup(size+sizeof(TLLChunk), PageSize)``, but
+    # since we know ``size`` is a (small) constant, we know the requested size
+    # is one page:
+    assert roundup(size+sizeof(TLLChunk), PageSize) == PageSize
+    var old = a.llmem # can be nil and is correct with nil
+    a.llmem = cast[PLLChunk](osAllocPages(PageSize))
+    incCurrMem(a, PageSize)
+    a.llmem.size = PageSize - sizeof(TLLChunk)
     a.llmem.acc = sizeof(TLLChunk)
+    a.llmem.next = old
   result = cast[pointer](cast[TAddress](a.llmem) + a.llmem.acc)
   dec(a.llmem.size, size)
   inc(a.llmem.acc, size)
   zeroMem(result, size)
   
+proc llDeallocAll(a: var TAllocator) =
+  var it = a.llmem
+  while it != nil:
+    # we know each block in the list has the size of 1 page:
+    var next = it.next
+    osDeallocPages(it, PageSize)
+    it = next
+  
 proc IntSetGet(t: TIntSet, key: int): PTrunk = 
   var it = t.data[key and high(t.data)]
   while it != nil: 
@@ -218,6 +231,24 @@ proc Excl(s: var TIntSet, key: int) =
     var u = key and TrunkMask
     t.bits[u shr IntShift] = t.bits[u shr IntShift] and not
         (1 shl (u and IntMask))
+
+iterator elements(t: TIntSet): int {.inline.} =
+  # while traversing it is forbidden to change the set!
+  for h in 0..high(t.data):
+    var r = t.data[h]
+    while r != nil:
+      var i = 0
+      while i <= high(r.bits):
+        var w = r.bits[i] # taking a copy of r.bits[i] here is correct, because
+        # modifying operations are not allowed during traversation
+        var j = 0
+        while w != 0:         # test all remaining bits for zero
+          if (w and 1) != 0:  # the bit is set!
+            yield (r.key shl TrunkShift) or (i shl IntShift +% j)
+          inc(j)
+          w = w shr 1
+        inc(i)
+      r = r.next
    
 # ------------- chunk management ----------------------------------------------
 proc pageIndex(c: PChunk): int {.inline.} = 
@@ -508,9 +539,21 @@ proc isAllocatedPtr(a: TAllocator, p: pointer): bool =
         var c = cast[PBigChunk](c)
         result = p == addr(c.data) and cast[ptr TFreeCell](p).zeroField >% 1
 
+proc deallocOsPages(a: var TAllocator) =
+  # we free every 'ordinarily' allocated page by iterating over the page
+  # bits:
+  for p in elements(a.chunkStarts): 
+    var page = cast[PChunk](p shl pageShift)
+    var size = if page.size < PageSize: PageSize else: page.size
+    osDeallocPages(page, size)
+  # And then we free the pages that are in use for the page bits:
+  llDeallocAll(a)
+
 var
   allocator {.rtlThreadVar.}: TAllocator
 
+proc deallocOsPages = deallocOsPages(allocator)
+
 # ---------------------- interface to programs -------------------------------
 
 when not defined(useNimRtl):
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 3ef39902a..75cac97ba 100755
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -212,8 +212,10 @@ proc quitOrDebug() {.inline.} =
     endbStep() # call the debugger
 
 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 raiseHook != nil:
+    if not raiseHook(e): return
+  GC_disable() # a bad thing is an error in the GC while raising an exception
   ThreadGlobals()
   if ||excHandler != nil:
     pushCurrentException(e)
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 80d9b1495..a6d351799 100755
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -107,9 +107,6 @@ proc writeln[Ty](f: TFile, x: openArray[Ty]) =
   for i in items(x): write(f, i)
   write(f, "\n")
 
-proc rawEcho(x: string) {.inline, compilerproc.} = write(stdout, x)
-proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n")
-
 # interface to the C procs:
 proc fopen(filename, mode: CString): pointer {.importc: "fopen", noDecl.}
 
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index c5264e4e2..8e94e60f5 100755
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -102,24 +102,15 @@ when defined(Windows):
     stdcall, dynlib: "kernel32", importc: "TerminateThread".}
     
   type
-    TThreadVarSlot {.compilerproc.} = distinct int32
+    TThreadVarSlot = distinct int32
 
-  proc TlsAlloc(): TThreadVarSlot {.
+  proc ThreadVarAlloc(): TThreadVarSlot {.
     importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
-  proc TlsSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
+  proc ThreadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
     importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
-  proc TlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
+  proc ThreadVarGetValue(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".}
@@ -225,7 +216,7 @@ type
   TGcThread {.pure.} = object
     sys: TSysThread
     next, prev: PGcThread
-    stackBottom, stackTop: pointer
+    stackBottom, stackTop, threadLocalStorage: pointer
     stackSize: int
     g: TGlobals
     locksLen: int
@@ -242,6 +233,9 @@ var globalsSlot = ThreadVarAlloc()
 proc ThisThread(): PGcThread {.compilerRtl, inl.} =
   result = cast[PGcThread](ThreadVarGetValue(globalsSlot))
 
+proc GetThreadLocalVars(): pointer {.compilerRtl, inl.} =
+  result = cast[PGcThread](ThreadVarGetValue(globalsSlot)).threadLocalStorage
+
 # create for the main thread. Note: do not insert this data into the list
 # of all threads; it's not to be stopped etc.
 when not defined(useNimRtl):
@@ -295,11 +289,14 @@ type
   TThread* {.pure, final.}[TParam] = object of TGcThread ## Nimrod thread.
     fn: proc (p: TParam)
     data: TParam
+
+when not defined(boehmgc) and not hasSharedHeap:
+  proc deallocOsPages()
   
 template ThreadProcWrapperBody(closure: expr) =
   ThreadVarSetValue(globalsSlot, closure)
   var t = cast[ptr TThread[TParam]](closure)
-  when not hasSharedHeap:
+  when not defined(boehmgc) and not hasSharedHeap:
     # init the GC for this thread:
     setStackBottom(addr(t))
     initGC()
@@ -309,6 +306,7 @@ template ThreadProcWrapperBody(closure: expr) =
     t.fn(t.data)
   finally:
     unregisterThread(t)
+    when defined(deallocOsPages): deallocOsPages()
   
 {.push stack_trace:off.}
 when defined(windows):