summary refs log tree commit diff stats
path: root/tests/parallel
diff options
context:
space:
mode:
Diffstat (limited to 'tests/parallel')
-rw-r--r--tests/parallel/nim.cfg2
-rw-r--r--tests/parallel/t10913.nim20
-rw-r--r--tests/parallel/t5000.nim25
-rw-r--r--tests/parallel/t7535.nim11
-rw-r--r--tests/parallel/t9691.nim9
-rw-r--r--tests/parallel/tarray_of_channels.nim39
-rw-r--r--tests/parallel/tblocking_channel.nim39
-rw-r--r--tests/parallel/tconvexhull.nim60
-rw-r--r--tests/parallel/tdeepcopy.nim55
-rw-r--r--tests/parallel/tdeepcopy2.nim38
-rw-r--r--tests/parallel/tdisjoint_slice1.nim51
-rw-r--r--tests/parallel/tflowvar.nim38
-rw-r--r--tests/parallel/tforstmt.nim25
-rw-r--r--tests/parallel/tgc_unsafe.nim32
-rw-r--r--tests/parallel/tgc_unsafe2.nim38
-rw-r--r--tests/parallel/tguard1.nim41
-rw-r--r--tests/parallel/tguard2.nim27
-rw-r--r--tests/parallel/tinvalid_array_bounds.nim26
-rw-r--r--tests/parallel/tinvalid_counter_usage.nim26
-rw-r--r--tests/parallel/tlet_spawn.nim28
-rw-r--r--tests/parallel/tmissing_deepcopy.nim42
-rw-r--r--tests/parallel/tnon_disjoint_slice1.nim26
-rw-r--r--tests/parallel/tparfind.nim29
-rw-r--r--tests/parallel/tpi.nim27
-rw-r--r--tests/parallel/tptr_to_ref.nim71
-rw-r--r--tests/parallel/treadafterwrite.nim31
-rw-r--r--tests/parallel/tsendtwice.nim65
-rw-r--r--tests/parallel/tsimple_array_checks.nim75
-rw-r--r--tests/parallel/tsysspawn.nim64
-rw-r--r--tests/parallel/tsysspawnbadarg.nim9
-rw-r--r--tests/parallel/tuseafterdef.nim34
-rw-r--r--tests/parallel/twaitany.nim34
32 files changed, 1137 insertions, 0 deletions
diff --git a/tests/parallel/nim.cfg b/tests/parallel/nim.cfg
new file mode 100644
index 000000000..d0d2a9305
--- /dev/null
+++ b/tests/parallel/nim.cfg
@@ -0,0 +1,2 @@
+threads:on
+--experimental
diff --git a/tests/parallel/t10913.nim b/tests/parallel/t10913.nim
new file mode 100644
index 000000000..191939100
--- /dev/null
+++ b/tests/parallel/t10913.nim
@@ -0,0 +1,20 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  errormsg: "'spawn'ed function cannot have a 'typed' or 'untyped' parameter"
+"""
+
+# bug #10913
+
+import threadpool
+
+proc useParallel*[T](unused: T) =
+  # use a generic T here to show the problem.
+  {.push experimental: "parallel".}
+  parallel:
+    for i in 0..4:
+      spawn echo "echo in parallel"
+  sync()
+  
+  {.pop.}
+
+useParallel(1)
diff --git a/tests/parallel/t5000.nim b/tests/parallel/t5000.nim
new file mode 100644
index 000000000..1dd47a61c
--- /dev/null
+++ b/tests/parallel/t5000.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''50005000'''
+  disabled: "true"
+"""
+
+# XXX this seems to deadlock certain Linux machines
+
+import threadpool, strutils
+
+proc foo(x: int): string = $x
+
+proc main() =
+  var a = newSeq[int]()
+  for i in 1..10000:
+    add(a, i)
+
+  var s = 0
+  for i in a:
+    s += parseInt(^spawn(foo(i)))
+  echo s
+
+setMaxPoolSize 2
+
+parallel:
+  spawn main()
diff --git a/tests/parallel/t7535.nim b/tests/parallel/t7535.nim
new file mode 100644
index 000000000..7817a1c9e
--- /dev/null
+++ b/tests/parallel/t7535.nim
@@ -0,0 +1,11 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  errormsg: "'spawn' takes a call expression; got: proc (x: uint32) = echo [x]"
+"""
+
+import threadpool
+
+# bug #7535
+proc print_parallel_nok(r: uint32) =
+  for x in 0..r:
+    spawn (proc (x: uint32) = echo x)
diff --git a/tests/parallel/t9691.nim b/tests/parallel/t9691.nim
new file mode 100644
index 000000000..254f03416
--- /dev/null
+++ b/tests/parallel/t9691.nim
@@ -0,0 +1,9 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  errormsg: "'spawn'ed function cannot have a 'typed' or 'untyped' parameter"
+"""
+
+# bug #9691
+
+import threadpool
+spawn echo()
diff --git a/tests/parallel/tarray_of_channels.nim b/tests/parallel/tarray_of_channels.nim
new file mode 100644
index 000000000..9479227aa
--- /dev/null
+++ b/tests/parallel/tarray_of_channels.nim
@@ -0,0 +1,39 @@
+discard """
+sortoutput: true
+output: '''
+(x: 0.0)
+(x: 0.0)
+(x: 0.0)
+test
+test
+test
+'''
+disabled: "openbsd"
+"""
+
+# bug #2257
+import threadpool
+
+type StringChannel = Channel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc consumer(ix : int) {.thread.} =
+  echo channels[ix].recv() ###### not GC-safe: 'channels'
+  echo globalB
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when true:
+  main()
diff --git a/tests/parallel/tblocking_channel.nim b/tests/parallel/tblocking_channel.nim
new file mode 100644
index 000000000..f3ccd166a
--- /dev/null
+++ b/tests/parallel/tblocking_channel.nim
@@ -0,0 +1,39 @@
+discard """
+output: ""
+disabled: "freebsd" # see #15725
+"""
+
+import threadpool, os
+
+var chan: Channel[int]
+
+chan.open(2)
+chan.send(1)
+chan.send(2)
+doAssert(not chan.trySend(3)) # At this point chan is at max capacity
+
+proc receiver() =
+    doAssert(chan.recv() == 1)
+    doAssert(chan.recv() == 2)
+    doAssert(chan.recv() == 3)
+    doAssert(chan.recv() == 4)
+    doAssert(chan.recv() == 5)
+
+var msgSent = false
+
+proc emitter() =
+    chan.send(3)
+    msgSent = true
+
+spawn emitter()
+# At this point emitter should be stuck in `send`
+sleep(50) # Sleep a bit to ensure that it is still stuck
+doAssert(not msgSent)
+
+spawn receiver()
+sleep(50) # Sleep a bit to let receicer consume the messages
+doAssert(msgSent) # Sender should be unblocked
+
+doAssert(chan.trySend(4))
+chan.send(5)
+sync()
diff --git a/tests/parallel/tconvexhull.nim b/tests/parallel/tconvexhull.nim
new file mode 100644
index 000000000..a89aa910b
--- /dev/null
+++ b/tests/parallel/tconvexhull.nim
@@ -0,0 +1,60 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''
+'''
+"""
+
+# parallel convex hull for Nim bigbreak
+# nim c --threads:on -d:release pconvex_hull.nim
+import algorithm, sequtils, threadpool
+
+type Point = tuple[x, y: float]
+
+proc cmpPoint(a, b: Point): int =
+  result = cmp(a.x, b.x)
+  if result == 0:
+    result = cmp(a.y, b.y)
+
+template cross[T](o, a, b: T): untyped =
+  (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x)
+
+template pro(): untyped =
+  while lr1 > 0 and cross(result[lr1 - 1], result[lr1], p[i]) <= 0:
+    discard result.pop
+    lr1 -= 1
+  result.add(p[i])
+  lr1 += 1
+
+proc half[T](p: seq[T]; upper: bool): seq[T] =
+  var i, lr1: int
+  result = @[]
+  lr1 = -1
+  if upper:
+    i = 0
+    while i <= high(p):
+      pro()
+      i += 1
+  else:
+    i = high(p)
+    while i >= low(p):
+      pro()
+      i -= 1
+  discard result.pop
+
+proc convex_hull[T](points: var seq[T], cmp: proc(x, y: T): int {.closure.}) : seq[T] =
+  if len(points) < 2: return points
+  points.sort(cmp)
+  var ul: array[2, FlowVar[seq[T]]]
+  parallel:
+    for k in 0..ul.high:
+      ul[k] = spawn half[T](points, k == 0)
+  result = concat(^ul[0], ^ul[1])
+
+var s = map(toSeq(0..9999), proc(x: int): Point = (float(x div 100), float(x mod 100)))
+# On some runs, this pool size reduction will set the "shutdown" attribute on the
+# worker thread that executes our spawned task, before we can read the flowvars.
+setMaxPoolSize 2
+
+for i in 0..2:
+  doAssert convex_hull[Point](s, cmpPoint) ==
+      @[(0.0, 0.0), (99.0, 0.0), (99.0, 99.0), (0.0, 99.0)]
diff --git a/tests/parallel/tdeepcopy.nim b/tests/parallel/tdeepcopy.nim
new file mode 100644
index 000000000..96ca15ca3
--- /dev/null
+++ b/tests/parallel/tdeepcopy.nim
@@ -0,0 +1,55 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''
+13 abc
+called deepCopy for int
+called deepCopy for int
+done999 999
+'''
+"""
+
+import threadpool
+
+block one:
+  type
+    PBinaryTree = ref object
+      le, ri: PBinaryTree
+      value: int
+
+  proc main =
+    var x: PBinaryTree
+    deepCopy(x, PBinaryTree(ri: PBinaryTree(le: PBinaryTree(value: 13))))
+    var y: string
+    deepCopy y, "abc"
+    echo x.ri.le.value, " ", y
+
+  main()
+
+
+block two:
+  type
+    Bar[T] = object
+      x: T
+
+  proc `=deepCopy`[T](b: ref Bar[T]): ref Bar[T] =
+    result.new
+    result.x = b.x
+    when T is int:
+      echo "called deepCopy for int"
+    else:
+      echo "called deepCopy for something else"
+
+  proc foo(b: ref Bar[int]): int = 999
+
+# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()':
+
+  proc main =
+    var dummy: ref Bar[int]
+    new(dummy)
+    dummy.x = 44
+    #parallel:
+    let f = spawn foo(dummy)
+    let b = spawn foo(dummy)
+    echo "done", ^f, " ", ^b
+
+  main()
diff --git a/tests/parallel/tdeepcopy2.nim b/tests/parallel/tdeepcopy2.nim
new file mode 100644
index 000000000..e8305173d
--- /dev/null
+++ b/tests/parallel/tdeepcopy2.nim
@@ -0,0 +1,38 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''
+called deepCopy for int
+called deepCopy for int
+done999 999
+'''
+"""
+
+import threadpool
+
+
+type
+  Bar[T] = object
+    x: T
+
+proc `=deepCopy`[T](b: ref Bar[T]): ref Bar[T] =
+  result.new
+  result.x = b.x
+  when T is int:
+    echo "called deepCopy for int"
+  else:
+    echo "called deepCopy for something else"
+
+proc foo(b: ref Bar[int]): int = 999
+
+# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()':
+
+proc main =
+  var dummy: ref Bar[int]
+  new(dummy)
+  dummy.x = 44
+  #parallel:
+  let f = spawn foo(dummy)
+  let b = spawn foo(dummy)
+  echo "done", ^f, " ", ^b
+
+main()
diff --git a/tests/parallel/tdisjoint_slice1.nim b/tests/parallel/tdisjoint_slice1.nim
new file mode 100644
index 000000000..6892e7383
--- /dev/null
+++ b/tests/parallel/tdisjoint_slice1.nim
@@ -0,0 +1,51 @@
+discard """
+  matrix: "--mm:refc"
+  outputsub: "EVEN 28"
+"""
+
+import threadpool, locks
+
+block one:
+  proc odd(a: int) =  echo "ODD  ", a
+  proc even(a: int) = echo "EVEN ", a
+
+  proc main() =
+    var a: array[0..30, int]
+    for i in low(a)..high(a): a[i] = i
+    parallel:
+      var i = 0
+      while i <= 29:
+        spawn even(a[i])
+        spawn odd(a[i+1])
+        inc i, 2
+        # is correct here
+
+  main()
+
+
+block two:
+  var echoLock: Lock
+  initLock echoLock
+
+  proc f(a: openArray[int]) =
+    for x in a:
+      withLock echoLock:
+        echo x
+
+  proc f(a: int) =
+    withLock echoLock:
+      echo a
+
+  proc main() =
+    var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9]
+    parallel:
+      spawn f(a[0..2])
+      #spawn f(a[16..30])
+      var i = 3
+      while i <= 8:
+        spawn f(a[i])
+        spawn f(a[i+1])
+        inc i, 2
+        # is correct here
+
+  main()
diff --git a/tests/parallel/tflowvar.nim b/tests/parallel/tflowvar.nim
new file mode 100644
index 000000000..e44b29a87
--- /dev/null
+++ b/tests/parallel/tflowvar.nim
@@ -0,0 +1,38 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''foobarfoobar
+bazbearbazbear
+
+1'''
+  cmd: "nim $target --threads:on $options $file"
+  disabled: "openbsd"
+"""
+
+import threadpool
+
+proc computeSomething(a, b: string): string = a & b & a & b & "\n"
+
+proc main =
+  let fvA = spawn computeSomething("foo", "bar")
+  let fvB = spawn computeSomething("baz", "bear")
+
+  echo(^fvA, ^fvB)
+
+main()
+sync()
+
+
+type
+  TIntSeq = seq[int]
+
+proc t(): TIntSeq =
+  result = @[1]
+
+proc p(): int =
+  var a: FlowVar[TIntSeq]
+  parallel:
+    var aa = spawn t()
+    a = aa
+  result = (^a)[0]
+
+echo p()
diff --git a/tests/parallel/tforstmt.nim b/tests/parallel/tforstmt.nim
new file mode 100644
index 000000000..58de833f3
--- /dev/null
+++ b/tests/parallel/tforstmt.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''3
+4
+5
+6
+7'''
+  sortoutput: true
+"""
+
+import threadpool, os
+
+proc p(x: int) =
+  os.sleep(100 - x*10)
+  echo x
+
+proc testFor(a, b: int; foo: var openArray[int]) =
+  parallel:
+    for i in max(a, 0) .. min(b, foo.high):
+      spawn p(foo[i])
+
+var arr = [0, 1, 2, 3, 4, 5, 6, 7]
+
+testFor(3, 10, arr)
+
+
diff --git a/tests/parallel/tgc_unsafe.nim b/tests/parallel/tgc_unsafe.nim
new file mode 100644
index 000000000..baf0dc24a
--- /dev/null
+++ b/tests/parallel/tgc_unsafe.nim
@@ -0,0 +1,32 @@
+discard """
+  errormsg: "'consumer' is not GC-safe"
+  line: 19
+"""
+
+# bug #2257
+import threadpool
+
+type StringChannel = Channel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc consumer(ix : int) {.thread.} =
+  echo channels[ix].recv() ###### not GC-safe: 'channels'
+  echo global
+  echo globalB
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when true:
+  main()
diff --git a/tests/parallel/tgc_unsafe2.nim b/tests/parallel/tgc_unsafe2.nim
new file mode 100644
index 000000000..7d98dafcb
--- /dev/null
+++ b/tests/parallel/tgc_unsafe2.nim
@@ -0,0 +1,38 @@
+discard """
+  errormsg: "'consumer' is not GC-safe as it calls 'track'"
+  nimout: '''tgc_unsafe2.nim(21, 6) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory [GcUnsafe2]
+tgc_unsafe2.nim(25, 6) Warning: 'track' is not GC-safe as it calls 'trick' [GcUnsafe2]
+tgc_unsafe2.nim(27, 6) Error: 'consumer' is not GC-safe as it calls 'track'
+'''
+"""
+
+import threadpool
+
+type StringChannel = Channel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc trick(ix: int) =
+  echo global.x
+  echo channels[ix].recv()
+
+proc track(ix: int) = trick(ix)
+
+proc consumer(ix: int) {.thread.} =
+  track(ix)
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when true:
+  main()
diff --git a/tests/parallel/tguard1.nim b/tests/parallel/tguard1.nim
new file mode 100644
index 000000000..f4c92319b
--- /dev/null
+++ b/tests/parallel/tguard1.nim
@@ -0,0 +1,41 @@
+discard """
+output: "90"
+"""
+
+
+when false:
+  template lock(a, b: ptr Lock; body: stmt) =
+    if cast[int](a) < cast[int](b):
+      pthread_mutex_lock(a)
+      pthread_mutex_lock(b)
+    else:
+      pthread_mutex_lock(b)
+      pthread_mutex_lock(a)
+    {.locks: [a, b].}:
+      try:
+        body
+      finally:
+        pthread_mutex_unlock(a)
+        pthread_mutex_unlock(b)
+
+type
+  ProtectedCounter[T] = object
+    i {.guard: L.}: T
+    L: int
+
+var
+  c: ProtectedCounter[int]
+
+c.i = 89
+
+template atomicRead(L, x): untyped =
+  {.locks: [L].}:
+    x
+
+proc main =
+  {.locks: [c.L].}:
+    inc c.i
+    discard
+  echo(atomicRead(c.L, c.i))
+
+main()
diff --git a/tests/parallel/tguard2.nim b/tests/parallel/tguard2.nim
new file mode 100644
index 000000000..661893bb5
--- /dev/null
+++ b/tests/parallel/tguard2.nim
@@ -0,0 +1,27 @@
+discard """
+  errormsg: "unguarded access: c.i"
+  line: 25
+"""
+
+type
+  ProtectedCounter[T] = object
+    i {.guard: L.}: T
+    L: int
+
+var
+  c: ProtectedCounter[int]
+
+c.i = 89
+
+template atomicRead(L, x): untyped =
+  {.locks: [L].}:
+    x
+
+proc main =
+  {.locks: [c.L].}:
+    inc c.i
+    discard
+  echo(atomicRead(c.L, c.i))
+  echo c.i
+
+main()
diff --git a/tests/parallel/tinvalid_array_bounds.nim b/tests/parallel/tinvalid_array_bounds.nim
new file mode 100644
index 000000000..8dc93c33f
--- /dev/null
+++ b/tests/parallel/tinvalid_array_bounds.nim
@@ -0,0 +1,26 @@
+discard """
+  matrix: "--mm:refc"
+  errormsg: "cannot prove (i)..(i) disjoint from (i + 1)..(i + 1)"
+  line: 21
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..30, int]
+  parallel:
+    spawn f(a[0..15])
+    spawn f(a[16..30])
+    var i = 0
+    while i <= 30:
+      spawn f(a[i])
+      spawn f(a[i+1])
+      inc i
+      #inc i  # inc i, 2  would be correct here
+
+main()
diff --git a/tests/parallel/tinvalid_counter_usage.nim b/tests/parallel/tinvalid_counter_usage.nim
new file mode 100644
index 000000000..c6303c651
--- /dev/null
+++ b/tests/parallel/tinvalid_counter_usage.nim
@@ -0,0 +1,26 @@
+discard """
+  errormsg: "invalid usage of counter after increment"
+  line: 21
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..30, int]
+  parallel:
+    spawn f(a[0..15])
+    spawn f(a[16..30])
+    var i = 0
+    while i <= 30:
+      inc i
+      spawn f(a[i])
+      inc i
+      #spawn f(a[i+1])
+      #inc i  # inc i, 2  would be correct here
+
+main()
diff --git a/tests/parallel/tlet_spawn.nim b/tests/parallel/tlet_spawn.nim
new file mode 100644
index 000000000..853ffc443
--- /dev/null
+++ b/tests/parallel/tlet_spawn.nim
@@ -0,0 +1,28 @@
+discard """
+output: '''
+done999 999
+'''
+"""
+
+import std/[threadpool, os]
+
+proc foo(): int = 999
+
+# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()':
+
+proc main =
+  parallel:
+    let f = spawn foo()
+    let b = spawn foo()
+  echo "done", f, " ", b
+
+main()
+
+# bug #13781
+proc thread(): string =
+  os.sleep(1000)
+  return "ok"
+
+var fv = spawn thread()
+sync()
+doAssert ^fv == "ok"
diff --git a/tests/parallel/tmissing_deepcopy.nim b/tests/parallel/tmissing_deepcopy.nim
new file mode 100644
index 000000000..ea77936ad
--- /dev/null
+++ b/tests/parallel/tmissing_deepcopy.nim
@@ -0,0 +1,42 @@
+discard """
+  matrix: "--mm:refc"
+  ccodeCheck: "@'genericDeepCopy(' .*"
+  action: compile
+"""
+
+# bug #2286
+
+import threadPool
+
+type
+  Person = ref object
+    name: string
+    friend: Person
+
+var
+  people: seq[Person] = @[]
+
+proc newPerson(name:string): Person =
+  result.new()
+  result.name = name
+
+proc greet(p:Person) =
+  p.friend.name &= "-MUT" # this line crashes the program
+  echo "Person {",
+    " name:", p.name, "(", cast[int](addr p.name),"),",
+    " friend:", p.friend.name, "(", cast[int](addr p.friend.name),") }"
+
+proc setup =
+  for i in 0 ..< 10:
+    people.add newPerson("Person" & $(i + 1))
+  for i in 0 ..< 10:
+    people[i].friend = people[9-i]
+
+proc update =
+  parallel:
+    for i in 0 .. people.high:
+      spawn people[i].greet()
+
+when true:
+  setup()
+  update()
diff --git a/tests/parallel/tnon_disjoint_slice1.nim b/tests/parallel/tnon_disjoint_slice1.nim
new file mode 100644
index 000000000..51762187d
--- /dev/null
+++ b/tests/parallel/tnon_disjoint_slice1.nim
@@ -0,0 +1,26 @@
+discard """
+  matrix: "--mm:refc"
+  errormsg: "cannot prove (i)..(i) disjoint from (i + 1)..(i + 1)"
+  line: 21
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..30, int]
+  parallel:
+    #spawn f(a[0..15])
+    #spawn f(a[16..30])
+    var i = 0
+    while i <= 29:
+      spawn f(a[i])
+      spawn f(a[i+1])
+      inc i
+      #inc i  # inc i, 2  would be correct here
+
+main()
diff --git a/tests/parallel/tparfind.nim b/tests/parallel/tparfind.nim
new file mode 100644
index 000000000..cf1bc9336
--- /dev/null
+++ b/tests/parallel/tparfind.nim
@@ -0,0 +1,29 @@
+discard """
+  matrix: "--mm:refc"
+  output: "500"
+"""
+
+import threadpool, sequtils
+
+{.experimental: "parallel".}
+
+proc linearFind(a: openArray[int]; x, offset: int): int =
+  for i, y in a:
+    if y == x: return i+offset
+  result = -1
+
+proc parFind(a: seq[int]; x: int): int =
+  var results: array[4, int]
+  parallel:
+    if a.len >= 4:
+      let chunk = a.len div 4
+      results[0] = spawn linearFind(a[0 ..< chunk], x, 0)
+      results[1] = spawn linearFind(a[chunk ..< chunk*2], x, chunk)
+      results[2] = spawn linearFind(a[chunk*2 ..< chunk*3], x, chunk*2)
+      results[3] = spawn linearFind(a[chunk*3 ..< a.len], x, chunk*3)
+  result = max(results)
+
+
+let data = toSeq(0..1000)
+echo parFind(data, 500)
+
diff --git a/tests/parallel/tpi.nim b/tests/parallel/tpi.nim
new file mode 100644
index 000000000..cd965d585
--- /dev/null
+++ b/tests/parallel/tpi.nim
@@ -0,0 +1,27 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''3.141792613595791
+3.141792613595791'''
+"""
+
+import strutils, math, threadpool
+
+proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1)
+
+proc piU(n: int): float =
+  var ch = newSeq[FlowVar[float]](n+1)
+  for k in 0..ch.high:
+    ch[k] = spawn term(float(k))
+  for k in 0..ch.high:
+    result += ^ch[k]
+
+proc piS(n: int): float =
+  var ch = newSeq[float](n+1)
+  parallel:
+    for k in 0..ch.high:
+      ch[k] = spawn term(float(k))
+  for k in 0..ch.high:
+    result += ch[k]
+
+echo formatFloat(piU(5000))
+echo formatFloat(piS(5000))
diff --git a/tests/parallel/tptr_to_ref.nim b/tests/parallel/tptr_to_ref.nim
new file mode 100644
index 000000000..ae02c16e5
--- /dev/null
+++ b/tests/parallel/tptr_to_ref.nim
@@ -0,0 +1,71 @@
+# bug #2854
+
+# Test case for the compiler correctly detecting if a type used by a shared
+# global is gcsafe.
+
+import locks, threadpool, osproc
+
+const MAX_WORKERS = 50
+
+type
+  Killer* = object
+    lock:                      Lock
+    bailed    {.guard: lock.}: bool
+    processes {.guard: lock.}: array[0..MAX_WORKERS-1, ptr Process]
+
+# Hold a lock for a statement.
+template hold(lock: Lock, body: untyped) =
+  lock.acquire
+  defer: lock.release
+  {.locks: [lock].}:
+    body
+
+# Return an initialized Killer.
+proc initKiller*(): Killer =
+  initLock(result.lock)
+  result.lock.hold:
+    result.bailed = false
+    for i, _ in result.processes:
+      result.processes[i] = nil
+
+# Global Killer instance.
+var killer = initKiller()
+
+# remember that a process has been launched, killing it if we have bailed.
+proc launched*(process: ptr Process): int {.gcsafe.} =
+  result = killer.processes.high + 1
+  killer.lock.hold:
+    if killer.bailed:
+      process[].terminate()
+    else:
+      for i, _ in killer.processes:
+        if killer.processes[i] == nil:
+          killer.processes[i] = process
+          result = i
+      assert(result <= killer.processes.high)
+
+
+# A process has been finished with - remove the process from death row.
+# Return true if the process was still present, which will be the
+# case unless we have bailed.
+proc completed*(index: int): bool {.gcsafe.} =
+  result = true
+  if index <= killer.processes.high:
+    killer.lock.hold:
+      result = false
+      if killer.processes[index] != nil:
+        result = true
+        killer.processes[index] = nil
+
+
+# Terminate all the processes killer knows about, doing nothing if
+# already bailed.
+proc bail(): bool {.gcsafe.} =
+  killer.lock.hold:
+    result = not killer.bailed
+    if not killer.bailed:
+      killer.bailed = true
+      for i, process in killer.processes:
+        if process != nil:
+          process[].terminate
+          killer.processes[i] = nil
diff --git a/tests/parallel/treadafterwrite.nim b/tests/parallel/treadafterwrite.nim
new file mode 100644
index 000000000..12eb31402
--- /dev/null
+++ b/tests/parallel/treadafterwrite.nim
@@ -0,0 +1,31 @@
+discard """
+  errormsg: "'foo' not disjoint from 'foo'"
+  line: 23
+  disabled: "true"
+"""
+
+# bug #1597
+
+import strutils, math, threadpool
+
+type
+  BoxedFloat = object
+    value: float
+
+proc term(k: float): ptr BoxedFloat =
+  var temp = 4 * math.pow(-1, k) / (2*k + 1)
+  result = cast[ptr BoxedFloat](allocShared(sizeof(BoxedFloat)))
+  result.value = temp
+
+proc pi(n: int): float =
+  var ch = newSeq[ptr BoxedFloat](n+1)
+  parallel:
+    for k in 0..ch.high:
+      let foo = (spawn term(float(k)))
+      assert foo != nil
+  for k in 0..ch.high:
+    var temp = ch[k][].value
+    result += temp
+    deallocShared(ch[k])
+
+echo formatFloat(pi(5000))
diff --git a/tests/parallel/tsendtwice.nim b/tests/parallel/tsendtwice.nim
new file mode 100644
index 000000000..9f4a2e06e
--- /dev/null
+++ b/tests/parallel/tsendtwice.nim
@@ -0,0 +1,65 @@
+discard """
+  matrix: "--mm:refc"
+"""
+
+# bug #4776
+
+import tables, algorithm
+
+type
+  Base* = ref object of RootObj
+    someSeq: seq[int]
+    baseData: array[40000, byte]
+  Derived* = ref object of Base
+    data: array[40000, 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("ob", d)
+globalTable.add("ob2", d)
+globalTable.add("ob3", d)
+
+proc `<`(x, y: seq[int]): bool = x.len < y.len
+proc kvs(t: TableRef[string, Base]): seq[(string, seq[int])] =
+  for k, v in t.pairs: result.add (k, v.someSeq)
+  result.sort
+
+proc testThread(channel: ptr TableChannel) {.thread.} =
+  globalTable = channel[].recv()
+  var myObj: Base
+  deepCopy(myObj, globalTable["ob"])
+  myObj.someSeq = newSeq[int](100)
+  let table = channel[].recv() # same table
+  assert(table.contains("ob")) # fails!
+  assert(table.contains("ob2")) # fails!
+  assert(table.contains("ob3")) # fails!
+  assert table.kvs == globalTable.kvs # Last to see above spot checks first
+
+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()
diff --git a/tests/parallel/tsimple_array_checks.nim b/tests/parallel/tsimple_array_checks.nim
new file mode 100644
index 000000000..ab292f935
--- /dev/null
+++ b/tests/parallel/tsimple_array_checks.nim
@@ -0,0 +1,75 @@
+discard """
+sortoutput: true
+output: '''
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+Hello 1
+Hello 2
+Hello 3
+Hello 4
+Hello 5
+Hello 6
+'''
+"""
+
+# bug #2287
+
+import threadPool
+
+# If `nums` is an array instead of seq,
+# NONE of the iteration ways below work (including high / len-1)
+let nums = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+proc log(n:int) =
+  echo n
+
+proc main =
+  parallel:
+    for n in nums: # Error: cannot prove: i <= len(nums) + -1
+      spawn log(n)
+    #for i in 0 ..< nums.len: # Error: cannot prove: i <= len(nums) + -1
+    #for i in 0 .. nums.len-1: # WORKS!
+    #for i in 0 ..< nums.len: # WORKS!
+    #  spawn log(nums[i])
+
+# Array needs explicit size to work, probably related to issue #2287
+#const a: array[0..5, int] = [1,2,3,4,5,6]
+
+#const a = [1,2,3,4,5,6] # Doesn't work
+const a = @[1,2,3,4,5,6] # Doesn't work
+proc f(n: int) = echo "Hello ", n
+
+proc maino =
+  parallel:
+    # while loop doesn't work:
+    var i = 0
+    while i < a.high:
+      #for i in countup(0, a.high-1, 2):
+      spawn f(a[i])
+      spawn f(a[i+1])
+      i += 2
+
+maino() # Doesn't work outside a proc
+
+when true:
+  main()
+
+block two:
+  proc f(a: openArray[int]) =
+    discard
+
+  proc main() =
+    var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9]
+    parallel:
+      spawn f(a[0..2])
+
+
+  main()
\ No newline at end of file
diff --git a/tests/parallel/tsysspawn.nim b/tests/parallel/tsysspawn.nim
new file mode 100644
index 000000000..b7ecd1264
--- /dev/null
+++ b/tests/parallel/tsysspawn.nim
@@ -0,0 +1,64 @@
+discard """
+  output: '''4
+8
+(a: 1)
+2
+2
+'''
+  matrix: "--mm:refc"
+"""
+
+import threadpool
+
+var
+  x, y = 0
+
+proc p1 =
+  for i in 0 .. 10_000:
+    discard
+
+  atomicInc x
+
+proc p2 =
+  for i in 0 .. 10_000:
+    discard
+
+  atomicInc y, 2
+
+for i in 0.. 3:
+  spawn(p1())
+  spawn(p2())
+
+sync()
+
+echo x
+echo y
+
+
+#--------------------------------------------------------
+# issue #14014
+
+import threadpool
+
+type A = object
+    a: int
+
+proc f(t: typedesc): t =
+  t(a:1)
+
+let r = spawn f(A)
+echo ^r
+
+proc f2(x: static[int]): int =
+  x
+
+let r2 = spawn f2(2)
+echo ^r2
+
+type statint = static[int]
+
+proc f3(x: statint): int =
+  x
+
+let r3 = spawn f3(2)
+echo ^r3
diff --git a/tests/parallel/tsysspawnbadarg.nim b/tests/parallel/tsysspawnbadarg.nim
new file mode 100644
index 000000000..a8f1ed401
--- /dev/null
+++ b/tests/parallel/tsysspawnbadarg.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "'spawn' takes a call expression"
+  line: 9
+  cmd: "nim $target --threads:on $options $file"
+"""
+
+import threadpool
+
+let foo = spawn(1)
diff --git a/tests/parallel/tuseafterdef.nim b/tests/parallel/tuseafterdef.nim
new file mode 100644
index 000000000..64f835a1b
--- /dev/null
+++ b/tests/parallel/tuseafterdef.nim
@@ -0,0 +1,34 @@
+discard """
+  matrix: "--mm:refc"
+  disabled: true
+  errormsg: "(k)..(k) not disjoint from (k)..(k)"
+  line: 24
+  action: compile
+"""
+
+# bug #1597
+
+import strutils, math, threadpool
+
+type
+  BoxedFloat = object
+    value: float
+
+proc term(k: float): ptr BoxedFloat =
+  var temp = 4 * math.pow(-1, k) / (2*k + 1)
+  result = cast[ptr BoxedFloat](allocShared(sizeof(BoxedFloat)))
+  result.value = temp
+
+proc pi(n: int): float =
+  var ch = newSeq[ptr BoxedFloat](n+1)
+  parallel:
+    for k in 0..ch.high:
+      ch[k] = (spawn term(float(k)))
+      assert ch[k] != nil
+  for k in 0..ch.high:
+    var temp = ch[k][].value
+    result += temp
+    deallocShared(ch[k])
+
+
+echo formatFloat(pi(5000))
diff --git a/tests/parallel/twaitany.nim b/tests/parallel/twaitany.nim
new file mode 100644
index 000000000..d57c5f40f
--- /dev/null
+++ b/tests/parallel/twaitany.nim
@@ -0,0 +1,34 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''true'''
+"""
+
+# bug #7638
+import threadpool, os
+
+proc timer(d: int): int =
+  #echo fmt"sleeping {d}"
+  sleep(d)
+  #echo fmt"done {d}"
+  return d
+
+var durations = [1000, 1500, 2000]
+var tasks: seq[FlowVarBase] = @[]
+var results: seq[int] = @[]
+
+for i in 0 .. durations.high:
+  tasks.add spawn timer(durations[i])
+
+var index = blockUntilAny(tasks)
+while index != -1:
+  results.add ^cast[FlowVar[int]](tasks[index])
+  tasks.del(index)
+  #echo repr results
+  index = blockUntilAny(tasks)
+
+doAssert results.len == 3
+doAssert 1000 in results
+doAssert 1500 in results
+doAssert 2000 in results
+sync()
+echo "true"