diff options
author | Araq <rumpf_a@web.de> | 2011-06-04 23:55:10 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2011-06-04 23:55:10 +0200 |
commit | 24ed9d560fb7a694c90dc0a378549a06600fcbd0 (patch) | |
tree | be0f8f2b0f44387e8e2c9b75c8db0506aece9a0b /lib/system | |
parent | 5008b44467bf545287289087a13f7e53c3d242ff (diff) | |
download | Nim-24ed9d560fb7a694c90dc0a378549a06600fcbd0.tar.gz |
threads clean up their heap
Diffstat (limited to 'lib/system')
-rwxr-xr-x | lib/system/alloc.nim | 59 | ||||
-rwxr-xr-x | lib/system/excpt.nim | 4 | ||||
-rwxr-xr-x | lib/system/sysio.nim | 3 | ||||
-rwxr-xr-x | lib/system/threads.nim | 28 |
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): |