This commit is contained in:
Andreas Rumpf 2016-09-24 02:17:14 +02:00
commit 66bbf7518e
4 changed files with 114 additions and 29 deletions

View file

@ -52,6 +52,7 @@ proc deinitRawChannel(p: pointer) =
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
mode: LoadStoreMode) {.benign.} mode: LoadStoreMode) {.benign.}
proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel, proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
mode: LoadStoreMode) {.benign.} = mode: LoadStoreMode) {.benign.} =
var var
@ -71,6 +72,9 @@ proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
mode: LoadStoreMode) = mode: LoadStoreMode) =
template `+!`(p: pointer; x: int): pointer =
cast[pointer](cast[int](p) +% x)
var var
d = cast[ByteAddress](dest) d = cast[ByteAddress](dest)
s = cast[ByteAddress](src) s = cast[ByteAddress](src)
@ -93,7 +97,9 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
if s2 == nil: if s2 == nil:
unsureAsgnRef(x, s2) unsureAsgnRef(x, s2)
else: else:
unsureAsgnRef(x, copyString(cast[NimString](s2))) let y = copyDeepString(cast[NimString](s2))
#echo "loaded ", cast[int](y), " ", cast[string](y)
unsureAsgnRef(x, y)
dealloc(t.region, s2) dealloc(t.region, s2)
of tySequence: of tySequence:
var s2 = cast[PPointer](src)[] var s2 = cast[PPointer](src)[]
@ -107,26 +113,27 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
else: else:
sysAssert(dest != nil, "dest == nil") sysAssert(dest != nil, "dest == nil")
if mode == mStore: if mode == mStore:
x[] = alloc(t.region, seq.len *% mt.base.size +% GenericSeqSize) x[] = alloc0(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[ByteAddress](cast[PPointer](dest)[]) var dst = cast[ByteAddress](cast[PPointer](dest)[])
var dstseq = cast[PGenericSeq](dst)
dstseq.len = seq.len
dstseq.reserved = seq.len
for i in 0..seq.len-1: for i in 0..seq.len-1:
storeAux( storeAux(
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
GenericSeqSize), GenericSeqSize),
mt.base, t, mode) mt.base, t, mode)
var dstseq = cast[PGenericSeq](dst)
dstseq.len = seq.len
dstseq.reserved = seq.len
if mode != mStore: dealloc(t.region, s2) if mode != mStore: dealloc(t.region, s2)
of tyObject: of tyObject:
if mt.base != nil:
storeAux(dest, src, mt.base, t, mode)
else:
# copy type field: # copy type field:
var pint = cast[ptr PNimType](dest) var pint = cast[ptr PNimType](dest)
pint[] = cast[ptr PNimType](src)[] pint[] = cast[ptr PNimType](src)[]
if mt.base != nil:
storeAux(dest, src, mt.base, t, mode)
storeAux(dest, src, mt.node, t, mode) storeAux(dest, src, mt.node, t, mode)
of tyTuple: of tyTuple:
storeAux(dest, src, mt.node, t, mode) storeAux(dest, src, mt.node, t, mode)
@ -143,15 +150,24 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
else: else:
unsureAsgnRef(x, nil) unsureAsgnRef(x, nil)
else: else:
let size = if mt.base.kind == tyObject: cast[ptr PNimType](s)[].size #let size = if mt.base.kind == tyObject: cast[ptr PNimType](s)[].size
else: mt.base.size # else: mt.base.size
if mode == mStore: if mode == mStore:
x[] = alloc(t.region, size) let dyntype = when declared(usrToCell): usrToCell(s).typ
else: mt
let size = dyntype.base.size
# we store the real dynamic 'ref type' at offset 0, so that
# no information is lost
let a = alloc0(t.region, size+sizeof(pointer))
x[] = a
cast[PPointer](a)[] = dyntype
storeAux(a +! sizeof(pointer), s, dyntype.base, t, mode)
else: else:
var obj = newObj(mt, size) let dyntype = cast[ptr PNimType](s)[]
var obj = newObj(dyntype, dyntype.base.size)
unsureAsgnRef(x, obj) unsureAsgnRef(x, obj)
storeAux(x[], s, mt.base, t, mode) storeAux(x[], s +! sizeof(pointer), dyntype.base, t, mode)
if mode != mStore: dealloc(t.region, s) dealloc(t.region, s)
else: else:
copyMem(dest, src, mt.size) # copy raw bits copyMem(dest, src, mt.size) # copy raw bits
@ -194,10 +210,8 @@ template sendImpl(q: expr) {.immediate.} =
if q.mask == ChannelDeadMask: if q.mask == ChannelDeadMask:
sysFatal(DeadThreadError, "cannot send message; thread died") sysFatal(DeadThreadError, "cannot send message; thread died")
acquireSys(q.lock) acquireSys(q.lock)
var m: TMsg
shallowCopy(m, msg)
var typ = cast[PNimType](getTypeInfo(msg)) var typ = cast[PNimType](getTypeInfo(msg))
rawSend(q, addr(m), typ) rawSend(q, unsafeAddr(msg), typ)
q.elemType = typ q.elemType = typ
releaseSys(q.lock) releaseSys(q.lock)
signalSysCond(q.cond) signalSysCond(q.cond)

View file

@ -32,12 +32,6 @@ proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.benign.} =
genericDeepCopyAux(dest, src, m) genericDeepCopyAux(dest, src, m)
of nkNone: sysAssert(false, "genericDeepCopyAux") of nkNone: sysAssert(false, "genericDeepCopyAux")
proc copyDeepString(src: NimString): NimString {.inline.} =
if src != nil:
result = rawNewStringNoInit(src.len)
result.len = src.len
copyMem(addr(result.data), addr(src.data), src.len + 1)
proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) = proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
var var
d = cast[ByteAddress](dest) d = cast[ByteAddress](dest)
@ -70,10 +64,11 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
of tyObject: of tyObject:
# we need to copy m_type field for tyObject, as it could be empty for # we need to copy m_type field for tyObject, as it could be empty for
# sequence reallocations: # sequence reallocations:
var pint = cast[ptr PNimType](dest)
pint[] = cast[ptr PNimType](src)[]
if mt.base != nil: if mt.base != nil:
genericDeepCopyAux(dest, src, mt.base) genericDeepCopyAux(dest, src, mt.base)
else:
var pint = cast[ptr PNimType](dest)
pint[] = cast[ptr PNimType](src)[]
genericDeepCopyAux(dest, src, mt.node) genericDeepCopyAux(dest, src, mt.node)
of tyTuple: of tyTuple:
genericDeepCopyAux(dest, src, mt.node) genericDeepCopyAux(dest, src, mt.node)
@ -103,16 +98,16 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
else: else:
let realType = x.typ let realType = x.typ
let z = newObj(realType, realType.base.size) let z = newObj(realType, realType.base.size)
unsureAsgnRef(cast[PPointer](dest), z) unsureAsgnRef(cast[PPointer](dest), z)
x.typ = cast[PNimType](cast[int](z) or 1) x.typ = cast[PNimType](cast[int](z) or 1)
genericDeepCopyAux(z, s2, realType.base) genericDeepCopyAux(z, s2, realType.base)
x.typ = realType x.typ = realType
else: else:
let realType = mt let size = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[].size
let z = newObj(realType, realType.base.size) else: mt.base.size
let z = newObj(mt, size)
unsureAsgnRef(cast[PPointer](dest), z) unsureAsgnRef(cast[PPointer](dest), z)
genericDeepCopyAux(z, s2, realType.base) genericDeepCopyAux(z, s2, mt.base)
of tyPtr: of tyPtr:
# no cycle check here, but also not really required # no cycle check here, but also not really required
let s2 = cast[PPointer](src)[] let s2 = cast[PPointer](src)[]

View file

@ -110,6 +110,11 @@ proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
result.len = src.len result.len = src.len
copyMem(addr(result.data), addr(src.data), src.len + 1) copyMem(addr(result.data), addr(src.data), src.len + 1)
proc copyDeepString(src: NimString): NimString {.inline.} =
if src != nil:
result = rawNewStringNoInit(src.len)
result.len = src.len
copyMem(addr(result.data), addr(src.data), src.len + 1)
proc hashString(s: string): int {.compilerproc.} = proc hashString(s: string): int {.compilerproc.} =
# the compiler needs exactly the same hash function! # the compiler needs exactly the same hash function!

View file

@ -0,0 +1,71 @@
discard """
output: '''obj2 nil
obj nil
obj3 nil
3
obj2 nil
obj nil
obj3 nil'''
cmd: "nim c -r --threads:on $file"
"""
# bug #4776
import tables
type
Base* = ref object of RootObj
someSeq: seq[int]
baseData: array[400000, byte]
Derived* = ref object of Base
data: array[400000, byte]
type
ThreadPool = ref object
threads: seq[ptr Thread[ThreadArg]]
channels: seq[ThreadArg]
TableChannel = Channel[TableRef[string, Base]]
ThreadArg = ptr TableChannel
var globalTable {.threadvar.}: TableRef[string, Base]
globalTable = newTable[string, Base]()
let d = new(Derived)
globalTable.add("obj", d)
globalTable.add("obj2", d)
globalTable.add("obj3", d)
proc testThread(channel: ptr TableChannel) {.thread.} =
globalTable = channel[].recv()
for k, v in pairs globaltable:
echo k, " ", v.someSeq
var myObj: Base
deepCopy(myObj, globalTable["obj"])
myObj.someSeq = newSeq[int](100)
let table = channel[].recv() # same table
echo table.len
for k, v in mpairs table:
echo k, " ", v.someSeq
assert(table.contains("obj")) # fails!
assert(table.contains("obj2")) # fails!
assert(table.contains("obj3")) # fails!
var channel: TableChannel
proc newThreadPool(threadCount: int) = #: ThreadPool =
#new(result)
#result.threads = newSeq[ptr Thread[ThreadArg]](threadCount)
#var channel = cast[ptr TableChannel](allocShared0(sizeof(TableChannel)))
channel.open()
channel.send(globalTable)
channel.send(globalTable)
#createThread(threadPtr[], testThread, addr channel)
testThread(addr channel)
#result.threads[i] = threadPtr
proc stop(p: ThreadPool) =
for t in p.threads:
joinThread(t[])
dealloc(t)
newThreadPool(1)#.stop()