diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2020-07-04 07:37:24 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-04 07:37:24 +0200 |
commit | 1854d29781aff913ca6892cbf73df91b0399397e (patch) | |
tree | 4a71bc7988c753ef1acab28776edec691c6d27bd /tests | |
parent | 695154970d839add2fbbe9754e9e638511120729 (diff) | |
download | Nim-1854d29781aff913ca6892cbf73df91b0399397e.tar.gz |
scoped memory management (#14790)
* fixes the regressions * closes #13936 * scope based memory management implemented * enabled tcontrolflow.nim test case * final cleanups
Diffstat (limited to 'tests')
-rw-r--r-- | tests/arc/tarcmisc.nim | 36 | ||||
-rw-r--r-- | tests/arc/tcontrolflow.nim | 21 | ||||
-rw-r--r-- | tests/arc/tmovebug.nim | 6 | ||||
-rw-r--r-- | tests/arc/tthread.nim | 10 | ||||
-rw-r--r-- | tests/arc/tweave.nim | 154 | ||||
-rw-r--r-- | tests/async/testmanyasyncevents.nim | 3 | ||||
-rw-r--r-- | tests/casestmt/t12785.nim | 8 | ||||
-rw-r--r-- | tests/destructor/tdestructor.nim | 38 |
8 files changed, 240 insertions, 36 deletions
diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 898efd138..e66d9a75f 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -173,3 +173,39 @@ proc bug14495 = echo o[] bug14495() + +when false: + # bug #14396 + type + Spinny = ref object + t: ref int + text: string + + proc newSpinny*(): Spinny = + Spinny(t: new(int), text: "hello") + + proc spinnyLoop(x: ref int, spinny: sink Spinny) = + echo x[] + + proc start*(spinny: sink Spinny) = + spinnyLoop(spinny.t, spinny) + + var spinner1 = newSpinny() + spinner1.start() + + # bug #14345 + + type + SimpleLoopB = ref object + children: seq[SimpleLoopB] + parent: SimpleLoopB + + proc addChildLoop(self: SimpleLoopB, loop: SimpleLoopB) = + self.children.add loop + + proc setParent(self: SimpleLoopB, parent: SimpleLoopB) = + self.parent = parent + self.parent.addChildLoop(self) + + var l = SimpleLoopB() + l.setParent(l) diff --git a/tests/arc/tcontrolflow.nim b/tests/arc/tcontrolflow.nim index efe51cc32..478806567 100644 --- a/tests/arc/tcontrolflow.nim +++ b/tests/arc/tcontrolflow.nim @@ -11,15 +11,13 @@ begin true if end true 7 +##index 2 not in 0 .. 1## ''' cmd: "nim c --gc:arc -d:danger $file" - disabled: "true" """ # we use the -d:danger switch to detect uninitialized stack # slots more reliably (there shouldn't be any, of course). -# XXX Enable once scope based destruction works! - type Foo = object id: int @@ -68,12 +66,25 @@ proc run(data: Control) = evt.control = data if evt.button == 1: discard - else: + else: return - + echo data.x var c = Control(x: 7) run(c) +proc sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} = + var buf = newStringOfCap(200) + add(buf, "##") + add(buf, message) + add(buf, "##") + echo buf + +proc ifexpr(i, a, b: int) {.compilerproc, noinline.} = + sysFatal(IndexDefect, + if b < a: "index out of bounds, the container is empty" + else: "index " & $i & " not in " & $a & " .. " & $b) + +ifexpr(2, 0, 1) diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index 951979a46..ec0fce9a8 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -247,7 +247,7 @@ iterator combinations[T](s: openarray[T], k: int): seq[T] = break type - UndefEx = object of Exception + UndefEx = object of ValueError proc main2 = var delayedSyms = @[1, 2, 3] @@ -318,10 +318,10 @@ proc `=sink`(dest: var O2, src: O2) = var testSeq: O2 -proc Update(): void = +proc update() = # testSeq.add(0) # uncommenting this line fixes the leak testSeq = O2(s: @[]) testSeq.s.add(0) for i in 1..3: - Update() + update() diff --git a/tests/arc/tthread.nim b/tests/arc/tthread.nim index c653c753f..8a55a666e 100644 --- a/tests/arc/tthread.nim +++ b/tests/arc/tthread.nim @@ -14,7 +14,7 @@ type p: int MyObjRef = ref MyObj -proc `=destroy`(x: var MyObj) = +proc `=destroy`(x: var MyObj) = if x.p != 0: echo "destroyed" @@ -48,16 +48,16 @@ proc thread5(x: sink MyObjRef): MyObjRef = os.sleep(1000) result = x -proc ref_forwarding_test = +proc ref_forwarding_test = var x = new(MyObj) x[].p = 2 var y = spawn thread4(x) - -proc ref_sink_forwarding_test = + +proc ref_sink_forwarding_test = var x = new(MyObj) x[].p = 2 var y = spawn thread5(x) ref_forwarding_test() -ref_sink_forwarding_test() +ref_sink_forwarding_test() sync() diff --git a/tests/arc/tweave.nim b/tests/arc/tweave.nim new file mode 100644 index 000000000..220d65f97 --- /dev/null +++ b/tests/arc/tweave.nim @@ -0,0 +1,154 @@ +discard """ + outputsub: '''Success''' + cmd: '''nim c --gc:arc --threads:on $file''' + disabled: "bsd" +""" + +# bug #13936 + +import std/atomics + +const MemBlockSize = 256 + +type + ChannelSPSCSingle* = object + full{.align: 128.}: Atomic[bool] + itemSize*: uint8 + buffer*{.align: 8.}: UncheckedArray[byte] + +proc `=`( + dest: var ChannelSPSCSingle, + source: ChannelSPSCSingle + ) {.error: "A channel cannot be copied".} + +proc initialize*(chan: var ChannelSPSCSingle, itemsize: SomeInteger) {.inline.} = + ## If ChannelSPSCSingle is used intrusive another data structure + ## be aware that it should be the last part due to ending by UncheckedArray + ## Also due to 128 bytes padding, it automatically takes half + ## of the default MemBlockSize + assert itemsize.int in 0 .. int high(uint8) + assert itemSize.int + + sizeof(chan.itemsize) + + sizeof(chan.full) < MemBlockSize + + chan.itemSize = uint8 itemsize + chan.full.store(false, moRelaxed) + +func isEmpty*(chan: var ChannelSPSCSingle): bool {.inline.} = + not chan.full.load(moAcquire) + +func tryRecv*[T](chan: var ChannelSPSCSingle, dst: var T): bool {.inline.} = + ## Try receiving the item buffered in the channel + ## Returns true if successful (channel was not empty) + ## + ## ⚠ Use only in the consumer thread that reads from the channel. + assert (sizeof(T) == chan.itemsize.int) or + # Support dummy object + (sizeof(T) == 0 and chan.itemsize == 1) + + let full = chan.full.load(moAcquire) + if not full: + return false + dst = cast[ptr T](chan.buffer.addr)[] + chan.full.store(false, moRelease) + return true + +func trySend*[T](chan: var ChannelSPSCSingle, src: sink T): bool {.inline.} = + ## Try sending an item into the channel + ## Reurns true if successful (channel was empty) + ## + ## ⚠ Use only in the producer thread that writes from the channel. + assert (sizeof(T) == chan.itemsize.int) or + # Support dummy object + (sizeof(T) == 0 and chan.itemsize == 1) + + let full = chan.full.load(moAcquire) + if full: + return false + cast[ptr T](chan.buffer.addr)[] = src + chan.full.store(true, moRelease) + return true + +# Sanity checks +# ------------------------------------------------------------------------------ +when isMainModule: + + when not compileOption("threads"): + {.error: "This requires --threads:on compilation flag".} + + template sendLoop[T](chan: var ChannelSPSCSingle, + data: sink T, + body: untyped): untyped = + while not chan.trySend(data): + body + + template recvLoop[T](chan: var ChannelSPSCSingle, + data: var T, + body: untyped): untyped = + while not chan.tryRecv(data): + body + + type + ThreadArgs = object + ID: WorkerKind + chan: ptr ChannelSPSCSingle + + WorkerKind = enum + Sender + Receiver + + template Worker(id: WorkerKind, body: untyped): untyped {.dirty.} = + if args.ID == id: + body + + proc thread_func(args: ThreadArgs) = + + # Worker RECEIVER: + # --------- + # <- chan + # <- chan + # <- chan + # + # Worker SENDER: + # --------- + # chan <- 42 + # chan <- 53 + # chan <- 64 + Worker(Receiver): + var val: int + for j in 0 ..< 10: + args.chan[].recvLoop(val): + # Busy loop, in prod we might want to yield the core/thread timeslice + discard + echo " Receiver got: ", val + doAssert val == 42 + j*11 + + Worker(Sender): + doAssert args.chan.full.load(moRelaxed) == false + for j in 0 ..< 10: + let val = 42 + j*11 + args.chan[].sendLoop(val): + # Busy loop, in prod we might want to yield the core/thread timeslice + discard + echo "Sender sent: ", val + + proc main() = + echo "Testing if 2 threads can send data" + echo "-----------------------------------" + var threads: array[2, Thread[ThreadArgs]] + + var chan = cast[ptr ChannelSPSCSingle](allocShared(MemBlockSize)) + chan[].initialize(itemSize = sizeof(int)) + + createThread(threads[0], thread_func, ThreadArgs(ID: Receiver, chan: chan)) + createThread(threads[1], thread_func, ThreadArgs(ID: Sender, chan: chan)) + + joinThread(threads[0]) + joinThread(threads[1]) + + freeShared(chan) + + echo "-----------------------------------" + echo "Success" + + main() diff --git a/tests/async/testmanyasyncevents.nim b/tests/async/testmanyasyncevents.nim index 5a103736f..9fdd01b4f 100644 --- a/tests/async/testmanyasyncevents.nim +++ b/tests/async/testmanyasyncevents.nim @@ -1,8 +1,9 @@ discard """ output: ''' hasPendingOperations: false -triggerCount: 100 +triggerCount: 100 ''' +disabled: "windows" """ import asyncDispatch diff --git a/tests/casestmt/t12785.nim b/tests/casestmt/t12785.nim index bf0f30d42..7177fb9c2 100644 --- a/tests/casestmt/t12785.nim +++ b/tests/casestmt/t12785.nim @@ -3,6 +3,8 @@ discard """ output: '''copied copied 2 +destroyed +destroyed copied copied 2 @@ -37,9 +39,9 @@ proc test(a: range[0..1], arg: ObjWithDestructor) = inc iteration case a - of 0: - assert false - of 1: + of 0: + assert false + of 1: echo b if iteration == 2: break diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim index 9fd47fe00..e081eb251 100644 --- a/tests/destructor/tdestructor.nim +++ b/tests/destructor/tdestructor.nim @@ -1,27 +1,27 @@ discard """ - output: '''---- + output: '''----1 myobj constructed myobj destroyed ----- +----2 mygeneric1 constructed mygeneric1 destroyed ----- +----3 mygeneric2 constructed mygeneric2 destroyed myobj destroyed ----- +----4 mygeneric3 constructed mygeneric1 destroyed ----- +----5 mydistinctObj constructed myobj destroyed mygeneric2 destroyed ------------------- ----- ----- -myobj destroyed +------------------8 mygeneric1 destroyed ---- +----6 +myobj destroyed +----7 +---9 myobj destroyed myobj destroyed ''' @@ -114,19 +114,19 @@ proc mydistinctObj = echo "mydistinctObj constructed" -echo "----" +echo "----1" myobj() -echo "----" +echo "----2" mygeneric1() -echo "----" +echo "----3" mygeneric2[int](10) -echo "----" +echo "----4" mygeneric3() -echo "----" +echo "----5" mydistinctObj() proc caseobj = @@ -134,16 +134,16 @@ proc caseobj = var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10)) block: - echo "----" + echo "----6" var o2 = TCaseObj(kind: B, y: open()) block: - echo "----" + echo "----7" var o3 = TCaseObj(kind: D, innerKind: B, r: "test", p: TMyGeneric3[int, float, string](x: 10, y: 1.0, z: "test")) -echo "------------------" +echo "------------------8" caseobj() proc caseobj_test_sink: TCaseObj = @@ -153,7 +153,7 @@ proc caseobj_test_sink: TCaseObj = result = TCaseObj(kind: B, y: open()) -echo "---" +echo "---9" discard caseobj_test_sink() # issue #14315 |