summary refs log tree commit diff stats
path: root/tests/threads
diff options
context:
space:
mode:
Diffstat (limited to 'tests/threads')
-rw-r--r--tests/threads/nim.cfg1
-rw-r--r--tests/threads/t7172.nim34
-rw-r--r--tests/threads/t8535.nim30
-rw-r--r--tests/threads/tactors.nim13
-rw-r--r--[-rwxr-xr-x]tests/threads/threadex.nim22
-rw-r--r--tests/threads/tjsthreads.nim6
-rw-r--r--tests/threads/tmanyjoin.nim31
-rw-r--r--tests/threads/tmembug.nim51
-rw-r--r--tests/threads/tonthreadcreation.nim26
-rw-r--r--tests/threads/tracy_allocator.nim26
-rw-r--r--tests/threads/trecursive_actor.nim19
-rw-r--r--tests/threads/treusetvar.nim29
-rw-r--r--[-rwxr-xr-x]tests/threads/tthreadanalysis.nim15
-rwxr-xr-xtests/threads/tthreadanalysis2.nim52
-rw-r--r--tests/threads/tthreadanalysis3.nim51
-rw-r--r--[-rwxr-xr-x]tests/threads/tthreadheapviolation1.nim12
-rw-r--r--tests/threads/tthreadvars.nim79
-rw-r--r--tests/threads/ttryrecv.nim36
18 files changed, 376 insertions, 157 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/tactors.nim b/tests/threads/tactors.nim
deleted file mode 100644
index 45a03ebb7..000000000
--- a/tests/threads/tactors.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-discard """
-  outputsub: "150"
-"""
-
-import actors
-
-var
-  pool: TActorPool[int, void]
-createActorPool(pool)
-for i in 0 .. < 300:
-  pool.spawn(i, proc (x: int) {.thread.} = echo x)
-pool.join()
-
diff --git a/tests/threads/threadex.nim b/tests/threads/threadex.nim
index 0360c8c04..90119aee7 100755..100644
--- a/tests/threads/threadex.nim
+++ b/tests/threads/threadex.nim
@@ -1,21 +1,25 @@
 discard """
-  outputsub: "All rights reserved."
+  disabled: i386
+  outputsub: "Just a simple text for test"
 """
 
 type
   TMsgKind = enum
     mLine, mEof
-  TMsg = object {.pure, final.}
+  TMsg = object
     case k: TMsgKind
-    of mEof: nil
+    of mEof: discard
     of mLine: data: string
 
 var
-  producer, consumer: TThread[void]
-  chan: TChannel[TMsg]
+  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
@@ -23,16 +27,17 @@ proc consume() {.thread.} =
     atomicInc(printedLines)
 
 proc produce() {.thread.} =
+  prodId = getThreadId()
   var m: TMsg
-  var input = open("readme.txt")
+  var input = open("tests/dummy.txt")
   var line = ""
   while input.readLine(line):
     m.data = line
     chan.send(m)
   close(input)
-  m.k = mEof
+  m = TMsg(k: mEof)
   chan.send(m)
-  
+
 open(chan)
 createThread[void](consumer, consume)
 createThread[void](producer, produce)
@@ -40,5 +45,6 @@ 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/trecursive_actor.nim b/tests/threads/trecursive_actor.nim
deleted file mode 100644
index e2774704c..000000000
--- a/tests/threads/trecursive_actor.nim
+++ /dev/null
@@ -1,19 +0,0 @@
-discard """
-  outputsub: "0"
-"""
-
-import actors
-
-var
-  a: TActorPool[int, void]
-createActorPool(a)
-
-proc task(i: int) {.thread.} =
-  echo i
-  if i != 0: a.spawn (i-1, task)
-
-# count from 9 till 0 and check 0 is somewhere in the output
-a.spawn(9, task)
-a.join()
-
-
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
index 4edd51025..7fc3593c8 100755..100644
--- a/tests/threads/tthreadanalysis.nim
+++ b/tests/threads/tthreadanalysis.nim
@@ -1,18 +1,19 @@
 discard """
-  outputsub: "101"
-  cmd: "nimrod cc --hints:on --threads:on $# $#"
+  errormsg: "'threadFunc' is not GC-safe"
+  line: 38
+  cmd: "nim $target --hints:on --threads:on $options $file"
 """
 
 import os
 
 var
-  thr: array [0..5, TThread[tuple[a, b: int]]]
+  thr: array[0..5, Thread[tuple[a, b: int]]]
 
-proc doNothing() = nil
+proc doNothing() = discard
 
 type
   PNode = ref TNode
-  TNode = object {.pure.}
+  TNode {.pure.} = object
     le, ri: PNode
     data: string
 
@@ -34,9 +35,9 @@ proc echoLeTree(n: PNode) =
     echo it.data
     it = it.le
 
-proc threadFunc(interval: tuple[a, b: int]) {.thread.} = 
+proc threadFunc(interval: tuple[a, b: int]) {.thread.} =
   doNothing()
-  for i in interval.a..interval.b: 
+  for i in interval.a..interval.b:
     var r = buildTree(i)
     echoLeTree(r) # for local data
   echoLeTree(root) # and the same for foreign data :-)
diff --git a/tests/threads/tthreadanalysis2.nim b/tests/threads/tthreadanalysis2.nim
deleted file mode 100755
index 07f0e61fd..000000000
--- a/tests/threads/tthreadanalysis2.nim
+++ /dev/null
@@ -1,52 +0,0 @@
-discard """
-  file: "tthreadanalysis2.nim"
-  line: 42
-  errormsg: "write to foreign heap"
-  cmd: "nimrod cc --hints:on --threads:on $# $#"
-"""
-
-import os
-
-var
-  thr: array [0..5, TThread[tuple[a, b: int]]]
-
-proc doNothing() = nil
-
-type
-  PNode = ref TNode
-  TNode = object {.pure.}
-    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 = 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
-  root = buildTree(2) # BAD!
-  #echoLeTree(root) # and the same for foreign data :-)
-
-proc main =
-  root = buildTree(5)
-  for i in 0..high(thr):
-    createThread(thr[i], threadFunc, (i*100, i*100+50))
-  joinThreads(thr)
-
-main()
-
diff --git a/tests/threads/tthreadanalysis3.nim b/tests/threads/tthreadanalysis3.nim
deleted file mode 100644
index d7a838fec..000000000
--- a/tests/threads/tthreadanalysis3.nim
+++ /dev/null
@@ -1,51 +0,0 @@
-discard """
-  file: "tthreadanalysis3.nim"
-  line: 35
-  errormsg: "write to foreign heap"
-  cmd: "nimrod cc --hints:on --threads:on $# $#"
-"""
-
-import os
-
-var
-  thr: array [0..5, TThread[tuple[a, b: int]]]
-
-proc doNothing() = nil
-
-type
-  PNode = ref TNode
-  TNode = object {.pure.}
-    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 = 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*100, i*100+50))
-  joinThreads(thr)
-
-main()
-
diff --git a/tests/threads/tthreadheapviolation1.nim b/tests/threads/tthreadheapviolation1.nim
index 7ca6f7928..379bd55e6 100755..100644
--- a/tests/threads/tthreadheapviolation1.nim
+++ b/tests/threads/tthreadheapviolation1.nim
@@ -1,12 +1,12 @@
 discard """
-  line: 12
-  errormsg: "write to foreign heap"
-  cmd: "nimrod cc --hints:on --threads:on $# $#"
+  errormsg: "'horrible' is not GC-safe"
+  line: 11
+  cmd: "nim $target --hints:on --threads:on $options $file"
 """
 
-var 
+var
   global: string = "test string"
-  t: TThread[void]
+  t: Thread[void]
 
 proc horrible() {.thread.} =
   global = "string in thread local heap!"
@@ -16,5 +16,3 @@ proc horrible() {.thread.} =
 
 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)