diff options
Diffstat (limited to 'tests/threads')
-rw-r--r-- | tests/threads/nim.cfg | 1 | ||||
-rw-r--r-- | tests/threads/t7172.nim | 34 | ||||
-rw-r--r-- | tests/threads/t8535.nim | 30 | ||||
-rw-r--r-- | tests/threads/threadex.nim | 50 | ||||
-rw-r--r-- | tests/threads/tjsthreads.nim | 6 | ||||
-rw-r--r-- | tests/threads/tmanyjoin.nim | 31 | ||||
-rw-r--r-- | tests/threads/tmembug.nim | 51 | ||||
-rw-r--r-- | tests/threads/tonthreadcreation.nim | 26 | ||||
-rw-r--r-- | tests/threads/tracy_allocator.nim | 26 | ||||
-rw-r--r-- | tests/threads/treusetvar.nim | 29 | ||||
-rw-r--r-- | tests/threads/tthreadanalysis.nim | 52 | ||||
-rw-r--r-- | tests/threads/tthreadheapviolation1.nim | 18 | ||||
-rw-r--r-- | tests/threads/tthreadvars.nim | 79 | ||||
-rw-r--r-- | tests/threads/ttryrecv.nim | 36 |
14 files changed, 469 insertions, 0 deletions
diff --git a/tests/threads/nim.cfg b/tests/threads/nim.cfg new file mode 100644 index 000000000..b81c89721 --- /dev/null +++ b/tests/threads/nim.cfg @@ -0,0 +1 @@ +threads:on diff --git a/tests/threads/t7172.nim b/tests/threads/t7172.nim new file mode 100644 index 000000000..87e89417b --- /dev/null +++ b/tests/threads/t7172.nim @@ -0,0 +1,34 @@ +discard """ + disabled: i386 + output: ''' +In doStuff() +In initProcess() +TEST +initProcess() done +Crashes before getting here! +''' + joinable: false +""" + +import std/os +import std/typedthreads + +proc whatever() {.thread, nimcall.} = + echo("TEST") + +proc initProcess(): void = + echo("In initProcess()") + var thread: Thread[void] + createThread(thread, whatever) + joinThread(thread) + echo("initProcess() done") + +proc doStuff(): void = + echo("In doStuff()") + # ... + initProcess() + sleep(500) + # ... + echo("Crashes before getting here!") + +doStuff() diff --git a/tests/threads/t8535.nim b/tests/threads/t8535.nim new file mode 100644 index 000000000..a4296df11 --- /dev/null +++ b/tests/threads/t8535.nim @@ -0,0 +1,30 @@ +discard """ + disabled: i386 + output: '''0 +hello''' +""" + +type + CircAlloc*[Size: static[int], T] = tuple + baseArray: array[Size,T] + index: uint16 + +type + Job = object of RootObj + +var foo {.threadvar.}: CircAlloc[1, Job] + +when true: + echo foo.index + + +# bug #10795 +import asyncdispatch +import threadpool + +proc f1() = + waitFor sleepAsync(20) + echo "hello" + +spawn f1() +sync() diff --git a/tests/threads/threadex.nim b/tests/threads/threadex.nim new file mode 100644 index 000000000..90119aee7 --- /dev/null +++ b/tests/threads/threadex.nim @@ -0,0 +1,50 @@ +discard """ + disabled: i386 + outputsub: "Just a simple text for test" +""" + +type + TMsgKind = enum + mLine, mEof + TMsg = object + case k: TMsgKind + of mEof: discard + of mLine: data: string + +var + producer, consumer: Thread[void] + chan: Channel[TMsg] + printedLines = 0 + prodId: int + consId: int + +proc consume() {.thread.} = + consId = getThreadId() + while true: + var x = recv(chan) + if x.k == mEof: break + echo x.data + atomicInc(printedLines) + +proc produce() {.thread.} = + prodId = getThreadId() + var m: TMsg + var input = open("tests/dummy.txt") + var line = "" + while input.readLine(line): + m.data = line + chan.send(m) + close(input) + m = TMsg(k: mEof) + chan.send(m) + +open(chan) +createThread[void](consumer, consume) +createThread[void](producer, produce) +joinThread(consumer) +joinThread(producer) + +close(chan) +doAssert prodId != consId +echo printedLines + diff --git a/tests/threads/tjsthreads.nim b/tests/threads/tjsthreads.nim new file mode 100644 index 000000000..5122c9cd6 --- /dev/null +++ b/tests/threads/tjsthreads.nim @@ -0,0 +1,6 @@ +discard """ + targets: "js" + matrix: "--threads:on" +""" + +echo 123 diff --git a/tests/threads/tmanyjoin.nim b/tests/threads/tmanyjoin.nim new file mode 100644 index 000000000..af5bc460e --- /dev/null +++ b/tests/threads/tmanyjoin.nim @@ -0,0 +1,31 @@ +discard """ + disabled: i386 + outputsub: "129" +""" + +import os, locks + +type + MarkerObj = object + lock: Lock + counter: int + Marker = ptr MarkerObj + +const + ThreadsCount = 129 + SleepTime = 250 + +proc worker(p: Marker) {.thread.} = + acquire(p.lock) + inc(p.counter) + release(p.lock) + sleep(SleepTime) + +var p = cast[Marker](allocShared0(sizeof(MarkerObj))) +initLock(p.lock) +var ts = newSeq[Thread[Marker]](ThreadsCount) +for i in 0..<ts.len: + createThread(ts[i], worker, p) + +joinThreads(ts) +echo p.counter diff --git a/tests/threads/tmembug.nim b/tests/threads/tmembug.nim new file mode 100644 index 000000000..3618f0ecc --- /dev/null +++ b/tests/threads/tmembug.nim @@ -0,0 +1,51 @@ + +import std / [atomics, strutils, sequtils] + +type + BackendMessage* = object + field*: seq[int] + +var + chan1: Channel[BackendMessage] + chan2: Channel[BackendMessage] + +chan1.open() +chan2.open() + +proc routeMessage*(msg: BackendMessage) = + discard chan2.trySend(msg) + +var + recv: Thread[void] + stopToken: Atomic[bool] + +proc recvMsg() = + while not stopToken.load(moRelaxed): + let resp = chan1.tryRecv() + if resp.dataAvailable: + routeMessage(resp.msg) + echo "child consumes ", formatSize getOccupiedMem() + +createThread[void](recv, recvMsg) + +const MESSAGE_COUNT = 100 + +proc main() = + let msg: BackendMessage = BackendMessage(field: (0..500).toSeq()) + for j in 0..0: #100: + echo "New iteration" + + for _ in 1..MESSAGE_COUNT: + chan1.send(msg) + echo "After sending" + + var counter = 0 + while counter < MESSAGE_COUNT: + let resp = recv(chan2) + counter.inc + echo "After receiving ", formatSize getOccupiedMem() + + stopToken.store true, moRelaxed + joinThreads(recv) + +main() diff --git a/tests/threads/tonthreadcreation.nim b/tests/threads/tonthreadcreation.nim new file mode 100644 index 000000000..61529477d --- /dev/null +++ b/tests/threads/tonthreadcreation.nim @@ -0,0 +1,26 @@ +discard """ + disabled: i386 + matrix: "--mm:refc; --mm:orc --deepcopy:on" + output: '''some string here +dying some string here''' +""" + +var + someGlobal: string = "some string here" + perThread {.threadvar.}: string + +proc threadDied() {.gcsafe.} = + echo "dying ", perThread + +proc foo() {.thread.} = + onThreadDestruction threadDied + {.gcsafe.}: + deepCopy(perThread, someGlobal) + echo perThread + +proc main = + var t: Thread[void] + createThread[void](t, foo) + t.joinThread() + +main() diff --git a/tests/threads/tracy_allocator.nim b/tests/threads/tracy_allocator.nim new file mode 100644 index 000000000..f3b39f4dc --- /dev/null +++ b/tests/threads/tracy_allocator.nim @@ -0,0 +1,26 @@ +discard """ + disabled: i386 + output: '''true''' +""" + +var somethingElse {.threadvar.}: ref string + +type MyThread = Thread[void] + +proc asyncThread() {.thread.} = + new somethingElse + +var threads = newSeq[ptr Thread[void]](8) + +for c in 1..1_000: + #echo "Test " & $c + for i in 0..<threads.len: + var t = cast[ptr Thread[void]](alloc0(sizeof(MyThread))) + threads[i] = t + createThread(t[], asyncThread) + + for t in threads: + joinThread(t[]) + dealloc(t) + +echo "true" diff --git a/tests/threads/treusetvar.nim b/tests/threads/treusetvar.nim new file mode 100644 index 000000000..f0337801a --- /dev/null +++ b/tests/threads/treusetvar.nim @@ -0,0 +1,29 @@ +discard """ + disabled: i386 + outputsub: "65" +""" + +import locks + +type + MarkerObj = object + lock: Lock + counter: int + Marker = ptr MarkerObj + +const + ThreadsCount = 65 + +proc worker(p: Marker) {.thread.} = + acquire(p.lock) + inc(p.counter) + release(p.lock) + +var p = cast[Marker](allocShared0(sizeof(MarkerObj))) +initLock(p.lock) + +for i in 0..(ThreadsCount - 1): + var thread: Thread[Marker] + createThread(thread, worker, p) + joinThread(thread) +echo p.counter diff --git a/tests/threads/tthreadanalysis.nim b/tests/threads/tthreadanalysis.nim new file mode 100644 index 000000000..7fc3593c8 --- /dev/null +++ b/tests/threads/tthreadanalysis.nim @@ -0,0 +1,52 @@ +discard """ + errormsg: "'threadFunc' is not GC-safe" + line: 38 + cmd: "nim $target --hints:on --threads:on $options $file" +""" + +import os + +var + thr: array[0..5, Thread[tuple[a, b: int]]] + +proc doNothing() = discard + +type + PNode = ref TNode + TNode {.pure.} = object + le, ri: PNode + data: string + +var + root: PNode + +proc buildTree(depth: int): PNode = + if depth == 3: return nil + new(result) + result.le = buildTree(depth-1) + result.ri = buildTree(depth-1) + result.data = $depth + +proc echoLeTree(n: PNode) = + var it: PNode + it = nil + it = n + while it != nil: + echo it.data + it = it.le + +proc threadFunc(interval: tuple[a, b: int]) {.thread.} = + doNothing() + for i in interval.a..interval.b: + var r = buildTree(i) + echoLeTree(r) # for local data + echoLeTree(root) # and the same for foreign data :-) + +proc main = + root = buildTree(5) + for i in 0..high(thr): + createThread(thr[i], threadFunc, (i*3, i*3+2)) + joinThreads(thr) + +main() + diff --git a/tests/threads/tthreadheapviolation1.nim b/tests/threads/tthreadheapviolation1.nim new file mode 100644 index 000000000..379bd55e6 --- /dev/null +++ b/tests/threads/tthreadheapviolation1.nim @@ -0,0 +1,18 @@ +discard """ + errormsg: "'horrible' is not GC-safe" + line: 11 + cmd: "nim $target --hints:on --threads:on $options $file" +""" + +var + global: string = "test string" + t: Thread[void] + +proc horrible() {.thread.} = + global = "string in thread local heap!" + var x = global + var mydata = (x, "my string too") + echo global + +createThread[void](t, horrible) +joinThread(t) diff --git a/tests/threads/tthreadvars.nim b/tests/threads/tthreadvars.nim new file mode 100644 index 000000000..745e3562c --- /dev/null +++ b/tests/threads/tthreadvars.nim @@ -0,0 +1,79 @@ +discard """ +disabled: i386 +output: ''' +10 +1111 +1222 +3030303 +3060606 +6060606 +6121212 +3030903 +3061206 +3031503 +3061806 +5050505 +5101010 +''' +""" + +import typetraits + +var tls1 {.threadvar.}: int +var g0: int +var g1 {.global.}: int + +proc customInc(x: var int, delta: int) = + x += delta + +customInc(tls1, 10) +echo tls1 + +proc nonGenericProc: int = + var local: int + var nonGenericTls {.threadvar.}: int + var nonGenericGlobal {.global.}: int + var nonGenericMixedPragmas {.global, threadvar.}: int + + customInc local, 1000 + customInc nonGenericTls, 1 + customInc nonGenericGlobal, 10 + customInc nonGenericMixedPragmas, 100 + + return local + nonGenericTls + nonGenericGlobal + nonGenericMixedPragmas + +proc genericProc(T: typedesc): int = + var local: int + var genericTls {.threadvar.}: int + var genericGlobal {.global.}: int + var genericMixedPragmas {.global, threadvar.}: int + + customInc local, T.name.len * 1000000 + customInc genericTls, T.name.len * 1 + customInc genericGlobal, T.name.len * 100 + customInc genericMixedPragmas, T.name.len * 10000 + + return local + genericTls + genericGlobal + genericMixedPragmas + +echo nonGenericProc() +echo nonGenericProc() + +echo genericProc(int) +echo genericProc(int) + +echo genericProc(string) +echo genericProc(string) + +proc echoInThread[T]() {.thread.} = + echo genericProc(T) + echo genericProc(T) + +proc newEchoThread(T: typedesc) = + var t: Thread[void] + createThread(t, echoInThread[T]) + joinThreads(t) + +newEchoThread int +newEchoThread int +newEchoThread float + diff --git a/tests/threads/ttryrecv.nim b/tests/threads/ttryrecv.nim new file mode 100644 index 000000000..fcff94e78 --- /dev/null +++ b/tests/threads/ttryrecv.nim @@ -0,0 +1,36 @@ +discard """ + matrix: "--mm:refc" + outputsub: "channel is empty" +""" + +# bug #1816 + +from random import rand +from os import sleep + +type PComm = ptr Channel[int] + +proc doAction(outC: PComm) {.thread.} = + for i in 0 ..< 5: + sleep(rand(50)) + send(outC[], i) + +var + thr: Thread[PComm] + chan: Channel[int] + +open(chan) +createThread[PComm](thr, doAction, addr(chan)) + +while true: + let (flag, x) = tryRecv(chan) + if flag: + echo("received from chan: " & $x) + else: + echo "channel is empty" + break + +echo "Finished listening" + +joinThread(thr) +close(chan) |