shared untraced heap; bugfix: mem corruptions in message passing code
This commit is contained in:
parent
42e6130b2c
commit
81a917390b
8 changed files with 151 additions and 87 deletions
|
|
@ -977,23 +977,56 @@ proc alloc*(size: int): pointer {.noconv, rtl.}
|
||||||
## block has to be freed with ``realloc(block, 0)`` or
|
## block has to be freed with ``realloc(block, 0)`` or
|
||||||
## ``dealloc(block)``. The block is not initialized, so reading
|
## ``dealloc(block)``. The block is not initialized, so reading
|
||||||
## from it before writing to it is undefined behaviour!
|
## from it before writing to it is undefined behaviour!
|
||||||
|
## The allocated memory belongs to its allocating thread!
|
||||||
|
## Use `allocShared` to allocate from a shared heap.
|
||||||
proc alloc0*(size: int): pointer {.noconv, rtl.}
|
proc alloc0*(size: int): pointer {.noconv, rtl.}
|
||||||
## allocates a new memory block with at least ``size`` bytes. The
|
## allocates a new memory block with at least ``size`` bytes. The
|
||||||
## block has to be freed with ``realloc(block, 0)`` or
|
## block has to be freed with ``realloc(block, 0)`` or
|
||||||
## ``dealloc(block)``. The block is initialized with all bytes
|
## ``dealloc(block)``. The block is initialized with all bytes
|
||||||
## containing zero, so it is somewhat safer than ``alloc``.
|
## containing zero, so it is somewhat safer than ``alloc``.
|
||||||
|
## The allocated memory belongs to its allocating thread!
|
||||||
|
## Use `allocShared0` to allocate from a shared heap.
|
||||||
proc realloc*(p: Pointer, newsize: int): pointer {.noconv, rtl.}
|
proc realloc*(p: Pointer, newsize: int): pointer {.noconv, rtl.}
|
||||||
## grows or shrinks a given memory block. If p is **nil** then a new
|
## grows or shrinks a given memory block. If p is **nil** then a new
|
||||||
## memory block is returned. In either way the block has at least
|
## memory block is returned. In either way the block has at least
|
||||||
## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil**
|
## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil**
|
||||||
## ``realloc`` calls ``dealloc(p)``. In other cases the block has to
|
## ``realloc`` calls ``dealloc(p)``. In other cases the block has to
|
||||||
## be freed with ``dealloc``.
|
## be freed with ``dealloc``.
|
||||||
|
## The allocated memory belongs to its allocating thread!
|
||||||
|
## Use `reallocShared` to reallocate from a shared heap.
|
||||||
proc dealloc*(p: Pointer) {.noconv, rtl.}
|
proc dealloc*(p: Pointer) {.noconv, rtl.}
|
||||||
## frees the memory allocated with ``alloc``, ``alloc0`` or
|
## frees the memory allocated with ``alloc``, ``alloc0`` or
|
||||||
## ``realloc``. This procedure is dangerous! If one forgets to
|
## ``realloc``. This procedure is dangerous! If one forgets to
|
||||||
## free the memory a leak occurs; if one tries to access freed
|
## free the memory a leak occurs; if one tries to access freed
|
||||||
## memory (or just freeing it twice!) a core dump may happen
|
## memory (or just freeing it twice!) a core dump may happen
|
||||||
## or other memory may be corrupted.
|
## or other memory may be corrupted.
|
||||||
|
## The freed memory must belong to its allocating thread!
|
||||||
|
## Use `deallocShared` to deallocate from a shared heap.
|
||||||
|
|
||||||
|
proc allocShared*(size: int): pointer {.noconv, rtl.}
|
||||||
|
## allocates a new memory block on the shared heap with at
|
||||||
|
## least ``size`` bytes. The block has to be freed with
|
||||||
|
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
|
||||||
|
## is not initialized, so reading from it before writing to it is
|
||||||
|
## undefined behaviour!
|
||||||
|
proc allocShared0*(size: int): pointer {.noconv, rtl.}
|
||||||
|
## allocates a new memory block on the shared heap with at
|
||||||
|
## least ``size`` bytes. The block has to be freed with
|
||||||
|
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
|
||||||
|
## The block is initialized with all bytes
|
||||||
|
## containing zero, so it is somewhat safer than ``allocShared``.
|
||||||
|
proc reallocShared*(p: Pointer, newsize: int): pointer {.noconv, rtl.}
|
||||||
|
## grows or shrinks a given memory block on the heap. If p is **nil**
|
||||||
|
## then a new memory block is returned. In either way the block has at least
|
||||||
|
## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil**
|
||||||
|
## ``reallocShared`` calls ``deallocShared(p)``. In other cases the
|
||||||
|
## block has to be freed with ``deallocShared``.
|
||||||
|
proc deallocShared*(p: Pointer) {.noconv, rtl.}
|
||||||
|
## frees the memory allocated with ``allocShared``, ``allocShared0`` or
|
||||||
|
## ``reallocShared``. This procedure is dangerous! If one forgets to
|
||||||
|
## free the memory a leak occurs; if one tries to access freed
|
||||||
|
## memory (or just freeing it twice!) a core dump may happen
|
||||||
|
## or other memory may be corrupted.
|
||||||
|
|
||||||
proc assert*(cond: bool) {.magic: "Assert", noSideEffect.}
|
proc assert*(cond: bool) {.magic: "Assert", noSideEffect.}
|
||||||
## provides a means to implement `programming by contracts`:idx: in Nimrod.
|
## provides a means to implement `programming by contracts`:idx: in Nimrod.
|
||||||
|
|
|
||||||
|
|
@ -550,6 +550,35 @@ proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
|
||||||
var c = cast[PBigChunk](c)
|
var c = cast[PBigChunk](c)
|
||||||
result = p == addr(c.data) and cast[ptr TFreeCell](p).zeroField >% 1
|
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) =
|
proc deallocOsPages(a: var TMemRegion) =
|
||||||
# we free every 'ordinarily' allocated page by iterating over the page bits:
|
# we free every 'ordinarily' allocated page by iterating over the page bits:
|
||||||
for p in elements(a.chunkStarts):
|
for p in elements(a.chunkStarts):
|
||||||
|
|
@ -569,48 +598,17 @@ proc getOccupiedMem(a: TMemRegion): int {.inline.} =
|
||||||
template InstantiateForRegion(allocator: expr) =
|
template InstantiateForRegion(allocator: expr) =
|
||||||
proc deallocOsPages = deallocOsPages(allocator)
|
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 =
|
proc alloc(size: int): pointer =
|
||||||
when hasThreadSupport and hasSharedHeap: AcquireSys(HeapLock)
|
result = alloc(allocator, size)
|
||||||
result = unlockedAlloc(size)
|
|
||||||
when hasThreadSupport and hasSharedHeap: ReleaseSys(HeapLock)
|
|
||||||
|
|
||||||
proc alloc0(size: int): pointer =
|
proc alloc0(size: int): pointer =
|
||||||
result = alloc(size)
|
result = alloc0(allocator, size)
|
||||||
zeroMem(result, size)
|
|
||||||
|
|
||||||
proc dealloc(p: pointer) =
|
proc dealloc(p: pointer) =
|
||||||
when hasThreadSupport and hasSharedHeap: AcquireSys(HeapLock)
|
dealloc(allocator, p)
|
||||||
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)
|
|
||||||
|
|
||||||
proc realloc(p: pointer, newsize: int): pointer =
|
proc realloc(p: pointer, newsize: int): pointer =
|
||||||
if newsize > 0:
|
result = realloc(allocator, p, newsize)
|
||||||
result = alloc(newsize)
|
|
||||||
if p != nil:
|
|
||||||
copyMem(result, p, ptrSize(p))
|
|
||||||
dealloc(p)
|
|
||||||
elif p != nil:
|
|
||||||
dealloc(p)
|
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
proc countFreeMem(): int =
|
proc countFreeMem(): int =
|
||||||
|
|
@ -627,3 +625,37 @@ template InstantiateForRegion(allocator: expr) =
|
||||||
proc getTotalMem(): int = return allocator.currMem
|
proc getTotalMem(): int = return allocator.currMem
|
||||||
proc getOccupiedMem(): int = return getTotalMem() - getFreeMem()
|
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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,9 @@ proc contains(s: TCellSeq, c: PCell): bool {.inline.} =
|
||||||
proc add(s: var TCellSeq, c: PCell) {.inline.} =
|
proc add(s: var TCellSeq, c: PCell) {.inline.} =
|
||||||
if s.len >= s.cap:
|
if s.len >= s.cap:
|
||||||
s.cap = s.cap * 3 div 2
|
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))
|
copyMem(d, s.d, s.len * sizeof(PCell))
|
||||||
unlockedDealloc(s.d)
|
Dealloc(s.d)
|
||||||
s.d = d
|
s.d = d
|
||||||
# XXX: realloc?
|
# XXX: realloc?
|
||||||
s.d[s.len] = c
|
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) =
|
proc init(s: var TCellSeq, cap: int = 1024) =
|
||||||
s.len = 0
|
s.len = 0
|
||||||
s.cap = cap
|
s.cap = cap
|
||||||
s.d = cast[PCellArray](unlockedAlloc0(cap * sizeof(PCell)))
|
s.d = cast[PCellArray](Alloc0(cap * sizeof(PCell)))
|
||||||
|
|
||||||
proc deinit(s: var TCellSeq) =
|
proc deinit(s: var TCellSeq) =
|
||||||
unlockedDealloc(s.d)
|
Dealloc(s.d)
|
||||||
s.d = nil
|
s.d = nil
|
||||||
s.len = 0
|
s.len = 0
|
||||||
s.cap = 0
|
s.cap = 0
|
||||||
|
|
@ -70,7 +70,7 @@ const
|
||||||
InitCellSetSize = 1024 # must be a power of two!
|
InitCellSetSize = 1024 # must be a power of two!
|
||||||
|
|
||||||
proc Init(s: var TCellSet) =
|
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.max = InitCellSetSize-1
|
||||||
s.counter = 0
|
s.counter = 0
|
||||||
s.head = nil
|
s.head = nil
|
||||||
|
|
@ -79,10 +79,10 @@ proc Deinit(s: var TCellSet) =
|
||||||
var it = s.head
|
var it = s.head
|
||||||
while it != nil:
|
while it != nil:
|
||||||
var n = it.next
|
var n = it.next
|
||||||
unlockedDealloc(it)
|
Dealloc(it)
|
||||||
it = n
|
it = n
|
||||||
s.head = nil # play it safe here
|
s.head = nil # play it safe here
|
||||||
unlockedDealloc(s.data)
|
Dealloc(s.data)
|
||||||
s.data = nil
|
s.data = nil
|
||||||
s.counter = 0
|
s.counter = 0
|
||||||
|
|
||||||
|
|
@ -110,11 +110,11 @@ proc CellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
|
||||||
proc CellSetEnlarge(t: var TCellSet) =
|
proc CellSetEnlarge(t: var TCellSet) =
|
||||||
var oldMax = t.max
|
var oldMax = t.max
|
||||||
t.max = ((t.max+1)*2)-1
|
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:
|
for i in 0 .. oldmax:
|
||||||
if t.data[i] != nil:
|
if t.data[i] != nil:
|
||||||
CellSetRawInsert(t, n, t.data[i])
|
CellSetRawInsert(t, n, t.data[i])
|
||||||
unlockedDealloc(t.data)
|
Dealloc(t.data)
|
||||||
t.data = n
|
t.data = n
|
||||||
|
|
||||||
proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
|
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)
|
while t.data[h] != nil: h = nextTry(h, t.max)
|
||||||
sysAssert(t.data[h] == nil)
|
sysAssert(t.data[h] == nil)
|
||||||
# the new page descriptor goes into result
|
# the new page descriptor goes into result
|
||||||
result = cast[PPageDesc](unlockedAlloc0(sizeof(TPageDesc)))
|
result = cast[PPageDesc](Alloc0(sizeof(TPageDesc)))
|
||||||
result.next = t.head
|
result.next = t.head
|
||||||
result.key = key
|
result.key = key
|
||||||
t.head = result
|
t.head = result
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PInbox,
|
||||||
x[] = nil
|
x[] = nil
|
||||||
else:
|
else:
|
||||||
var ss = cast[NimString](s2)
|
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)
|
copyMem(ns, ss, ss.len+1 + GenericSeqSize)
|
||||||
x[] = ns
|
x[] = ns
|
||||||
else:
|
else:
|
||||||
|
|
@ -87,7 +87,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PInbox,
|
||||||
unsureAsgnRef(x, s2)
|
unsureAsgnRef(x, s2)
|
||||||
else:
|
else:
|
||||||
unsureAsgnRef(x, copyString(cast[NimString](s2)))
|
unsureAsgnRef(x, copyString(cast[NimString](s2)))
|
||||||
rawDealloc(t.region, s2)
|
Dealloc(t.region, s2)
|
||||||
of tySequence:
|
of tySequence:
|
||||||
var s2 = cast[ppointer](src)[]
|
var s2 = cast[ppointer](src)[]
|
||||||
var seq = cast[PGenericSeq](s2)
|
var seq = cast[PGenericSeq](s2)
|
||||||
|
|
@ -100,7 +100,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PInbox,
|
||||||
else:
|
else:
|
||||||
sysAssert(dest != nil)
|
sysAssert(dest != nil)
|
||||||
if mode == mStore:
|
if mode == mStore:
|
||||||
x[] = rawAlloc(t.region, seq.len *% mt.base.size +% GenericSeqSize)
|
x[] = Alloc(t.region, seq.len *% mt.base.size +% GenericSeqSize)
|
||||||
else:
|
else:
|
||||||
unsureAsgnRef(x, newObj(mt, seq.len * mt.base.size + GenericSeqSize))
|
unsureAsgnRef(x, newObj(mt, seq.len * mt.base.size + GenericSeqSize))
|
||||||
var dst = cast[taddress](cast[ppointer](dest)[])
|
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)
|
var dstseq = cast[PGenericSeq](dst)
|
||||||
dstseq.len = seq.len
|
dstseq.len = seq.len
|
||||||
dstseq.space = seq.len
|
dstseq.space = seq.len
|
||||||
if mode != mStore: rawDealloc(t.region, s2)
|
if mode != mStore: Dealloc(t.region, s2)
|
||||||
of tyObject:
|
of tyObject:
|
||||||
# copy type field:
|
# copy type field:
|
||||||
var pint = cast[ptr PNimType](dest)
|
var pint = cast[ptr PNimType](dest)
|
||||||
|
|
@ -136,7 +136,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PInbox,
|
||||||
unsureAsgnRef(x, nil)
|
unsureAsgnRef(x, nil)
|
||||||
else:
|
else:
|
||||||
if mode == mStore:
|
if mode == mStore:
|
||||||
x[] = rawAlloc(t.region, mt.base.size)
|
x[] = Alloc(t.region, mt.base.size)
|
||||||
else:
|
else:
|
||||||
# XXX we should use the dynamic type here too, but that is not stored in
|
# 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
|
# 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)
|
var obj = newObj(mt.base, mt.base.size)
|
||||||
unsureAsgnRef(x, obj)
|
unsureAsgnRef(x, obj)
|
||||||
storeAux(x[], s, mt.base, t, mode)
|
storeAux(x[], s, mt.base, t, mode)
|
||||||
if mode != mStore: rawDealloc(t.region, s)
|
if mode != mStore: Dealloc(t.region, s)
|
||||||
else:
|
else:
|
||||||
copyMem(dest, src, mt.size) # copy raw bits
|
copyMem(dest, src, mt.size) # copy raw bits
|
||||||
|
|
||||||
|
|
@ -154,7 +154,7 @@ proc rawSend(q: PInbox, data: pointer, typ: PNimType) =
|
||||||
if q.count >= cap:
|
if q.count >= cap:
|
||||||
# start with capicity for 2 entries in the queue:
|
# start with capicity for 2 entries in the queue:
|
||||||
if cap == 0: cap = 1
|
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 z = 0
|
||||||
var i = q.rd
|
var i = q.rd
|
||||||
var c = q.count
|
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)
|
copyMem(addr(n[z*typ.size]), addr(q.data[i*typ.size]), typ.size)
|
||||||
i = (i + 1) and q.mask
|
i = (i + 1) and q.mask
|
||||||
inc z
|
inc z
|
||||||
if q.data != nil: rawDealloc(q.region, q.data)
|
if q.data != nil: Dealloc(q.region, q.data)
|
||||||
q.data = n
|
q.data = n
|
||||||
q.mask = cap*2 - 1
|
q.mask = cap*2 - 1
|
||||||
q.wr = q.count
|
q.wr = q.count
|
||||||
|
|
|
||||||
|
|
@ -88,12 +88,18 @@ when defined(boehmgc):
|
||||||
proc realloc(p: Pointer, newsize: int): pointer =
|
proc realloc(p: Pointer, newsize: int): pointer =
|
||||||
result = boehmRealloc(p, newsize)
|
result = boehmRealloc(p, newsize)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc dealloc(p: Pointer) =
|
proc dealloc(p: Pointer) = boehmDealloc(p)
|
||||||
boehmDealloc(p)
|
|
||||||
|
|
||||||
proc unlockedAlloc(size: int): pointer {.inline.} = result = alloc(size)
|
proc allocShared(size: int): pointer =
|
||||||
proc unlockedAlloc0(size: int): pointer {.inline.} = result = alloc0(size)
|
result = boehmAlloc(size)
|
||||||
proc unlockedDealloc(p: pointer) {.inline.} = dealloc(p)
|
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() =
|
proc initGC() =
|
||||||
when defined(macosx): boehmGCinit()
|
when defined(macosx): boehmGCinit()
|
||||||
|
|
@ -136,20 +142,13 @@ when defined(boehmgc):
|
||||||
type
|
type
|
||||||
TMemRegion = object {.final, pure.}
|
TMemRegion = object {.final, pure.}
|
||||||
|
|
||||||
var
|
proc Alloc(r: var TMemRegion, size: int): pointer =
|
||||||
dummy {.rtlThreadVar.}: int
|
|
||||||
|
|
||||||
proc rawAlloc(r: var TMemRegion, size: int): pointer =
|
|
||||||
result = boehmAlloc(size)
|
result = boehmAlloc(size)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc rawAlloc0(r: var TMemRegion, size: int): pointer =
|
proc Alloc0(r: var TMemRegion, size: int): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
proc realloc(r: var TMemRegion, p: Pointer, newsize: int): pointer =
|
proc Dealloc(r: var TMemRegion, p: Pointer) = boehmDealloc(p)
|
||||||
result = boehmRealloc(p, newsize)
|
|
||||||
if result == nil: raiseOutOfMem()
|
|
||||||
proc rawDealloc(r: var TMemRegion, p: Pointer) = boehmDealloc(p)
|
|
||||||
|
|
||||||
proc deallocOsPages(r: var TMemRegion) {.inline.} = nil
|
proc deallocOsPages(r: var TMemRegion) {.inline.} = nil
|
||||||
proc deallocOsPages() {.inline.} = nil
|
proc deallocOsPages() {.inline.} = nil
|
||||||
|
|
||||||
|
|
@ -204,10 +203,6 @@ elif defined(nogc):
|
||||||
else:
|
else:
|
||||||
include "system/alloc"
|
include "system/alloc"
|
||||||
|
|
||||||
proc unlockedAlloc(size: int): pointer {.inline.}
|
|
||||||
proc unlockedAlloc0(size: int): pointer {.inline.}
|
|
||||||
proc unlockedDealloc(p: pointer) {.inline.}
|
|
||||||
|
|
||||||
include "system/cellsets"
|
include "system/cellsets"
|
||||||
sysAssert(sizeof(TCell) == sizeof(TFreeCell))
|
sysAssert(sizeof(TCell) == sizeof(TFreeCell))
|
||||||
include "system/gc"
|
include "system/gc"
|
||||||
|
|
|
||||||
|
|
@ -210,10 +210,7 @@ when not defined(useNimRtl):
|
||||||
echo "too large thread local storage size requested"
|
echo "too large thread local storage size requested"
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
when hasSharedHeap:
|
when hasSharedHeap and not defined(boehmgc) and not defined(nogc):
|
||||||
var heapLock: TSysLock
|
|
||||||
InitSysLock(HeapLock)
|
|
||||||
|
|
||||||
var
|
var
|
||||||
threadList: PGcThread
|
threadList: PGcThread
|
||||||
|
|
||||||
|
|
@ -275,19 +272,17 @@ template ThreadProcWrapperBody(closure: expr) =
|
||||||
var t = cast[ptr TThread[TMsg]](closure)
|
var t = cast[ptr TThread[TMsg]](closure)
|
||||||
when useStackMaskHack:
|
when useStackMaskHack:
|
||||||
var tls: TThreadLocalStorage
|
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:
|
# init the GC for this thread:
|
||||||
setStackBottom(addr(t))
|
setStackBottom(addr(t))
|
||||||
initGC()
|
initGC()
|
||||||
when hasSharedHeap:
|
when defined(registerThread):
|
||||||
t.stackBottom = addr(t)
|
t.stackBottom = addr(t)
|
||||||
registerThread(t)
|
registerThread(t)
|
||||||
if t.emptyFn == nil: t.dataFn(t.data)
|
if t.emptyFn == nil: t.dataFn(t.data)
|
||||||
else: t.emptyFn()
|
else: t.emptyFn()
|
||||||
#finally:
|
|
||||||
# XXX shut-down is not executed when the thread is forced down!
|
|
||||||
freeInbox(addr(t.inbox))
|
freeInbox(addr(t.inbox))
|
||||||
when hasSharedHeap: unregisterThread(t)
|
when defined(registerThread): unregisterThread(t)
|
||||||
when defined(deallocOsPages): deallocOsPages()
|
when defined(deallocOsPages): deallocOsPages()
|
||||||
# Since an unhandled exception terminates the whole process (!), there is
|
# Since an unhandled exception terminates the whole process (!), there is
|
||||||
# no need for a ``try finally`` here, nor would it be correct: The current
|
# no need for a ``try finally`` here, nor would it be correct: The current
|
||||||
|
|
|
||||||
19
todo.txt
19
todo.txt
|
|
@ -1,21 +1,28 @@
|
||||||
version 0.9.0
|
Version 0.8.14
|
||||||
=============
|
==============
|
||||||
|
|
||||||
- ``var T`` as a return type; easy to prove that location does not escape its
|
- ``var T`` as a return type; easy to prove that location does not escape its
|
||||||
stack frame
|
stack frame
|
||||||
|
- strutils.unindent
|
||||||
- document Nimrod's two phase symbol lookup for generics
|
- document Nimrod's two phase symbol lookup for generics
|
||||||
|
- make ^ available as operator
|
||||||
|
- make threadvar efficient again on linux after testing
|
||||||
|
- test the sort implementation again
|
||||||
|
- export re-entrant and non-reentrant locks and condition vars
|
||||||
|
|
||||||
|
|
||||||
|
version 0.9.0
|
||||||
|
=============
|
||||||
|
|
||||||
- add --deadlock_prevention:on|off switch? timeout for locks?
|
- add --deadlock_prevention:on|off switch? timeout for locks?
|
||||||
- bug: tfFinal not passed to generic
|
- bug: tfFinal not passed to generic
|
||||||
- bug: forward proc for generic seems broken
|
- bug: forward proc for generic seems broken
|
||||||
- test the sort implementation again
|
|
||||||
- warning for implicit openArray -> varargs convention
|
- warning for implicit openArray -> varargs convention
|
||||||
- implement explicit varargs
|
- implement explicit varargs
|
||||||
- tests: run modules that contain "#RUN_ME", compile the other
|
- tests: run modules that contain "#RUN_ME", compile the other
|
||||||
modules; run the GC tests
|
modules; run the GC tests
|
||||||
- fix overloading resolution
|
- change overloading resolution
|
||||||
- make ^ available as operator
|
|
||||||
- implement closures; implement proper coroutines
|
- implement closures; implement proper coroutines
|
||||||
- make threadvar efficient again on linux after testing
|
|
||||||
|
|
||||||
Bugs
|
Bugs
|
||||||
----
|
----
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,5 @@ Wiki: http://github.com/Araq/Nimrod/wiki.
|
||||||
|
|
||||||
Bug reports: http://github.com/Araq/Nimrod/issues.
|
Bug reports: http://github.com/Araq/Nimrod/issues.
|
||||||
|
|
||||||
|
For quickest feedback, join our IRC channel: irc://freenode/nimrod
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue