diff options
author | Araq <rumpf_a@web.de> | 2011-07-18 23:59:39 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2011-07-18 23:59:39 +0200 |
commit | 81a917390bdb61d07310c8faf31092f65acbfb53 (patch) | |
tree | 479042020adbe5b92b518733a80a3b9164c0abe4 /lib/system | |
parent | 42e6130b2c37345963c0b5469e12a287b88bf3eb (diff) | |
download | Nim-81a917390bdb61d07310c8faf31092f65acbfb53.tar.gz |
shared untraced heap; bugfix: mem corruptions in message passing code
Diffstat (limited to 'lib/system')
-rwxr-xr-x | lib/system/alloc.nim | 102 | ||||
-rwxr-xr-x | lib/system/cellsets.nim | 20 | ||||
-rwxr-xr-x | lib/system/inboxes.nim | 16 | ||||
-rwxr-xr-x | lib/system/mmdisp.nim | 33 | ||||
-rwxr-xr-x | lib/system/threads.nim | 13 |
5 files changed, 103 insertions, 81 deletions
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index efa372bcd..e3b1d589b 100755 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -550,6 +550,35 @@ proc isAllocatedPtr(a: TMemRegion, p: pointer): bool = var c = cast[PBigChunk](c) result = p == addr(c.data) and cast[ptr TFreeCell](p).zeroField >% 1 +proc ptrSize(p: pointer): int = + var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell)) + result = pageAddr(x).size - sizeof(TFreeCell) + +proc alloc(allocator: var TMemRegion, size: int): pointer = + result = rawAlloc(allocator, size+sizeof(TFreeCell)) + cast[ptr TFreeCell](result).zeroField = 1 # mark it as used + sysAssert(not isAllocatedPtr(allocator, result)) + result = cast[pointer](cast[TAddress](result) +% sizeof(TFreeCell)) + +proc alloc0(allocator: var TMemRegion, size: int): pointer = + result = alloc(size) + zeroMem(result, size) + +proc dealloc(allocator: var TMemRegion, p: pointer) = + var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell)) + sysAssert(cast[ptr TFreeCell](x).zeroField == 1) + rawDealloc(allocator, x) + sysAssert(not isAllocatedPtr(allocator, x)) + +proc realloc(allocator: var TMemRegion, p: pointer, newsize: int): pointer = + if newsize > 0: + result = alloc(allocator, newsize) + if p != nil: + copyMem(result, p, ptrSize(p)) + dealloc(allocator, p) + elif p != nil: + dealloc(allocator, p) + proc deallocOsPages(a: var TMemRegion) = # we free every 'ordinarily' allocated page by iterating over the page bits: for p in elements(a.chunkStarts): @@ -569,48 +598,17 @@ proc getOccupiedMem(a: TMemRegion): int {.inline.} = template InstantiateForRegion(allocator: expr) = proc deallocOsPages = deallocOsPages(allocator) - proc unlockedAlloc(size: int): pointer = - result = rawAlloc(allocator, size+sizeof(TFreeCell)) - cast[ptr TFreeCell](result).zeroField = 1 # mark it as used - sysAssert(not isAllocatedPtr(allocator, result)) - result = cast[pointer](cast[TAddress](result) +% sizeof(TFreeCell)) - - proc unlockedAlloc0(size: int): pointer = - result = unlockedAlloc(size) - zeroMem(result, size) - - proc unlockedDealloc(p: pointer) = - var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell)) - sysAssert(cast[ptr TFreeCell](x).zeroField == 1) - rawDealloc(allocator, x) - sysAssert(not isAllocatedPtr(allocator, x)) - proc alloc(size: int): pointer = - when hasThreadSupport and hasSharedHeap: AcquireSys(HeapLock) - result = unlockedAlloc(size) - when hasThreadSupport and hasSharedHeap: ReleaseSys(HeapLock) + result = alloc(allocator, size) proc alloc0(size: int): pointer = - result = alloc(size) - zeroMem(result, size) + result = alloc0(allocator, size) proc dealloc(p: pointer) = - when hasThreadSupport and hasSharedHeap: AcquireSys(HeapLock) - unlockedDealloc(p) - when hasThreadSupport and hasSharedHeap: ReleaseSys(HeapLock) - - proc ptrSize(p: pointer): int = - var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell)) - result = pageAddr(x).size - sizeof(TFreeCell) + dealloc(allocator, p) proc realloc(p: pointer, newsize: int): pointer = - if newsize > 0: - result = alloc(newsize) - if p != nil: - copyMem(result, p, ptrSize(p)) - dealloc(p) - elif p != nil: - dealloc(p) + result = realloc(allocator, p, newsize) when false: proc countFreeMem(): int = @@ -627,3 +625,37 @@ template InstantiateForRegion(allocator: expr) = proc getTotalMem(): int = return allocator.currMem proc getOccupiedMem(): int = return getTotalMem() - getFreeMem() + # -------------------- shared heap region ---------------------------------- + when hasThreadSupport: + var sharedHeap: TMemRegion + var heapLock: TSysLock + InitSysLock(HeapLock) + + proc allocShared(size: int): pointer = + when hasThreadSupport: + AcquireSys(HeapLock) + result = alloc(sharedHeap, size) + ReleaseSys(HeapLock) + else: + result = alloc(size) + + proc allocShared0(size: int): pointer = + result = allocShared(size) + zeroMem(result, size) + + proc deallocShared(p: pointer) = + when hasThreadSupport: + AcquireSys(HeapLock) + dealloc(sharedHeap, p) + ReleaseSys(HeapLock) + else: + dealloc(p) + + proc reallocShared(p: pointer, newsize: int): pointer = + when hasThreadSupport: + AcquireSys(HeapLock) + result = realloc(sharedHeap, p, newsize) + ReleaseSys(HeapLock) + else: + result = realloc(p, newsize) + diff --git a/lib/system/cellsets.nim b/lib/system/cellsets.nim index 7502636fa..b8bfbaf6d 100755 --- a/lib/system/cellsets.nim +++ b/lib/system/cellsets.nim @@ -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](unlockedAlloc(s.cap * sizeof(PCell))) + var d = cast[PCellArray](Alloc(s.cap * sizeof(PCell))) copyMem(d, s.d, s.len * sizeof(PCell)) - unlockedDealloc(s.d) + Dealloc(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](unlockedAlloc0(cap * sizeof(PCell))) + s.d = cast[PCellArray](Alloc0(cap * sizeof(PCell))) proc deinit(s: var TCellSeq) = - unlockedDealloc(s.d) + Dealloc(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](unlockedAlloc0(InitCellSetSize * sizeof(PPageDesc))) + s.data = cast[PPageDescArray](Alloc0(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 - unlockedDealloc(it) + Dealloc(it) it = n s.head = nil # play it safe here - unlockedDealloc(s.data) + Dealloc(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](unlockedAlloc0((t.max + 1) * sizeof(PPageDesc))) + var n = cast[PPageDescArray](Alloc0((t.max + 1) * sizeof(PPageDesc))) for i in 0 .. oldmax: if t.data[i] != nil: CellSetRawInsert(t, n, t.data[i]) - unlockedDealloc(t.data) + Dealloc(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) sysAssert(t.data[h] == nil) # the new page descriptor goes into result - result = cast[PPageDesc](unlockedAlloc0(sizeof(TPageDesc))) + result = cast[PPageDesc](Alloc0(sizeof(TPageDesc))) result.next = t.head result.key = key t.head = result diff --git a/lib/system/inboxes.nim b/lib/system/inboxes.nim index b2db103cb..d4a4b1eb4 100755 --- a/lib/system/inboxes.nim +++ b/lib/system/inboxes.nim @@ -77,7 +77,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PInbox, x[] = nil else: var ss = cast[NimString](s2) - var ns = cast[NimString](rawAlloc(t.region, ss.len+1 + GenericSeqSize)) + var ns = cast[NimString](Alloc(t.region, ss.len+1 + GenericSeqSize)) copyMem(ns, ss, ss.len+1 + GenericSeqSize) x[] = ns else: @@ -87,7 +87,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PInbox, unsureAsgnRef(x, s2) else: unsureAsgnRef(x, copyString(cast[NimString](s2))) - rawDealloc(t.region, s2) + Dealloc(t.region, s2) of tySequence: var s2 = cast[ppointer](src)[] var seq = cast[PGenericSeq](s2) @@ -100,7 +100,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PInbox, else: sysAssert(dest != nil) if mode == mStore: - x[] = rawAlloc(t.region, seq.len *% mt.base.size +% GenericSeqSize) + x[] = Alloc(t.region, seq.len *% mt.base.size +% GenericSeqSize) else: unsureAsgnRef(x, newObj(mt, seq.len * mt.base.size + GenericSeqSize)) var dst = cast[taddress](cast[ppointer](dest)[]) @@ -113,7 +113,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PInbox, var dstseq = cast[PGenericSeq](dst) dstseq.len = seq.len dstseq.space = seq.len - if mode != mStore: rawDealloc(t.region, s2) + if mode != mStore: Dealloc(t.region, s2) of tyObject: # copy type field: var pint = cast[ptr PNimType](dest) @@ -136,7 +136,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PInbox, unsureAsgnRef(x, nil) else: if mode == mStore: - x[] = rawAlloc(t.region, mt.base.size) + x[] = Alloc(t.region, mt.base.size) else: # XXX we should use the dynamic type here too, but that is not stored in # the inbox at all --> use source[]'s object type? but how? we need a @@ -144,7 +144,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PInbox, var obj = newObj(mt.base, mt.base.size) unsureAsgnRef(x, obj) storeAux(x[], s, mt.base, t, mode) - if mode != mStore: rawDealloc(t.region, s) + if mode != mStore: Dealloc(t.region, s) else: copyMem(dest, src, mt.size) # copy raw bits @@ -154,7 +154,7 @@ proc rawSend(q: PInbox, data: pointer, typ: PNimType) = if q.count >= cap: # start with capicity for 2 entries in the queue: if cap == 0: cap = 1 - var n = cast[pbytes](rawAlloc0(q.region, cap*2*typ.size)) + var n = cast[pbytes](Alloc0(q.region, cap*2*typ.size)) var z = 0 var i = q.rd var c = q.count @@ -163,7 +163,7 @@ proc rawSend(q: PInbox, data: pointer, typ: PNimType) = copyMem(addr(n[z*typ.size]), addr(q.data[i*typ.size]), typ.size) i = (i + 1) and q.mask inc z - if q.data != nil: rawDealloc(q.region, q.data) + if q.data != nil: Dealloc(q.region, q.data) q.data = n q.mask = cap*2 - 1 q.wr = q.count diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 0cbee1d47..5d1371cf9 100755 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -88,12 +88,18 @@ when defined(boehmgc): proc realloc(p: Pointer, newsize: int): pointer = result = boehmRealloc(p, newsize) if result == nil: raiseOutOfMem() - proc dealloc(p: Pointer) = - boehmDealloc(p) + 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 allocShared(size: int): pointer = + result = boehmAlloc(size) + if result == nil: raiseOutOfMem() + proc allocShared0(size: int): pointer = + result = alloc(size) + zeroMem(result, size) + proc reallocShared(p: Pointer, newsize: int): pointer = + result = boehmRealloc(p, newsize) + if result == nil: raiseOutOfMem() + proc deallocShared(p: Pointer) = boehmDealloc(p) proc initGC() = when defined(macosx): boehmGCinit() @@ -136,20 +142,13 @@ when defined(boehmgc): type TMemRegion = object {.final, pure.} - var - dummy {.rtlThreadVar.}: int - - proc rawAlloc(r: var TMemRegion, size: int): pointer = + proc Alloc(r: var TMemRegion, size: int): pointer = result = boehmAlloc(size) if result == nil: raiseOutOfMem() - proc rawAlloc0(r: var TMemRegion, size: int): pointer = + proc Alloc0(r: var TMemRegion, size: int): pointer = result = alloc(size) zeroMem(result, size) - proc realloc(r: var TMemRegion, p: Pointer, newsize: int): pointer = - result = boehmRealloc(p, newsize) - if result == nil: raiseOutOfMem() - proc rawDealloc(r: var TMemRegion, p: Pointer) = boehmDealloc(p) - + proc Dealloc(r: var TMemRegion, p: Pointer) = boehmDealloc(p) proc deallocOsPages(r: var TMemRegion) {.inline.} = nil proc deallocOsPages() {.inline.} = nil @@ -204,10 +203,6 @@ elif defined(nogc): else: include "system/alloc" - proc unlockedAlloc(size: int): pointer {.inline.} - proc unlockedAlloc0(size: int): pointer {.inline.} - proc unlockedDealloc(p: pointer) {.inline.} - include "system/cellsets" sysAssert(sizeof(TCell) == sizeof(TFreeCell)) include "system/gc" diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 823844c55..ccca85cb7 100755 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -210,10 +210,7 @@ when not defined(useNimRtl): echo "too large thread local storage size requested" quit 1 - when hasSharedHeap: - var heapLock: TSysLock - InitSysLock(HeapLock) - + when hasSharedHeap and not defined(boehmgc) and not defined(nogc): var threadList: PGcThread @@ -275,19 +272,17 @@ template ThreadProcWrapperBody(closure: expr) = var t = cast[ptr TThread[TMsg]](closure) when useStackMaskHack: var tls: TThreadLocalStorage - when not defined(boehmgc) and not hasSharedHeap: + when not defined(boehmgc) and not defined(nogc) and not hasSharedHeap: # init the GC for this thread: setStackBottom(addr(t)) initGC() - when hasSharedHeap: + when defined(registerThread): t.stackBottom = addr(t) registerThread(t) if t.emptyFn == nil: t.dataFn(t.data) else: t.emptyFn() - #finally: - # XXX shut-down is not executed when the thread is forced down! freeInbox(addr(t.inbox)) - when hasSharedHeap: unregisterThread(t) + when defined(registerThread): unregisterThread(t) when defined(deallocOsPages): deallocOsPages() # Since an unhandled exception terminates the whole process (!), there is # no need for a ``try finally`` here, nor would it be correct: The current |