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/threadex.nim50
-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/treusetvar.nim29
-rw-r--r--tests/threads/tthreadanalysis.nim52
-rw-r--r--tests/threads/tthreadheapviolation1.nim18
-rw-r--r--tests/threads/tthreadvars.nim79
-rw-r--r--tests/threads/ttryrecv.nim36
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)