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.cfg1
-rw-r--r--tests/parallel/tgc_unsafe2.nim39
-rw-r--r--tests/parallel/tparfind.nim28
-rw-r--r--tests/parallel/tptr_to_ref.nim71
-rw-r--r--tests/parallel/treadafterwrite.nim2
-rw-r--r--tests/parallel/tuseafterdef.nim4
-rw-r--r--tests/parallel/twrong_refcounts.nim53
7 files changed, 195 insertions, 3 deletions
diff --git a/tests/parallel/nim.cfg b/tests/parallel/nim.cfg
index b81c89721..d0d2a9305 100644
--- a/tests/parallel/nim.cfg
+++ b/tests/parallel/nim.cfg
@@ -1 +1,2 @@
 threads:on
+--experimental
diff --git a/tests/parallel/tgc_unsafe2.nim b/tests/parallel/tgc_unsafe2.nim
new file mode 100644
index 000000000..ec4605fe9
--- /dev/null
+++ b/tests/parallel/tgc_unsafe2.nim
@@ -0,0 +1,39 @@
+discard """
+  line: 28
+  nimout: '''tgc_unsafe2.nim(22, 5) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory
+tgc_unsafe2.nim(26, 5) Warning: 'track' is not GC-safe as it calls 'trick'
+tgc_unsafe2.nim(28, 5) Error: 'consumer' is not GC-safe as it calls 'track'
+'''
+  errormsg: "'consumer' is not GC-safe as it calls 'track'"
+"""
+
+import threadpool
+
+type StringChannel = TChannel[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 isMainModule:
+  main()
diff --git a/tests/parallel/tparfind.nim b/tests/parallel/tparfind.nim
new file mode 100644
index 000000000..9de5012f5
--- /dev/null
+++ b/tests/parallel/tparfind.nim
@@ -0,0 +1,28 @@
+discard """
+  output: "500"
+"""
+
+import threadpool, sequtils
+
+{.experimental.}
+
+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/tptr_to_ref.nim b/tests/parallel/tptr_to_ref.nim
new file mode 100644
index 000000000..229c247ce
--- /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, foreign ptr Process]
+
+# Hold a lock for a statement.
+template hold(lock: Lock, body: stmt) =
+  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: foreign 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
index f59ad5ae0..12eb31402 100644
--- a/tests/parallel/treadafterwrite.nim
+++ b/tests/parallel/treadafterwrite.nim
@@ -12,7 +12,7 @@ type
   BoxedFloat = object
     value: float
 
-proc term(k: float): ptr BoxedFloat = 
+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
diff --git a/tests/parallel/tuseafterdef.nim b/tests/parallel/tuseafterdef.nim
index 95123e886..833c72a0a 100644
--- a/tests/parallel/tuseafterdef.nim
+++ b/tests/parallel/tuseafterdef.nim
@@ -7,11 +7,11 @@ discard """
 
 import strutils, math, threadpool
 
-type 
+type
   BoxedFloat = object
     value: float
 
-proc term(k: float): ptr BoxedFloat = 
+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
diff --git a/tests/parallel/twrong_refcounts.nim b/tests/parallel/twrong_refcounts.nim
new file mode 100644
index 000000000..db32a96d8
--- /dev/null
+++ b/tests/parallel/twrong_refcounts.nim
@@ -0,0 +1,53 @@
+discard """
+  output: "Success"
+"""
+
+import math, threadPool
+
+# ---
+
+type
+  Person = object
+    age: int
+    friend: ref Person
+
+var
+  people: seq[ref Person] = @[]
+
+proc newPerson(age:int): ref Person =
+  result.new()
+  result.age = age
+
+proc greet(p:Person) =
+  #echo p.age, ", ", p.friend.age
+  p.friend.age += 1
+
+# ---
+
+proc setup =
+  for i in 0 .. <20:
+    people.add newPerson(i + 1)
+  for i in 0 .. <20:
+    people[i].friend = people[random(20)]
+
+proc update =
+  var countA: array[20, int]
+  var countB: array[20, int]
+
+  for i, p in people:
+    countA[i] = getRefCount(p)
+  parallel:
+    for i in 0 .. people.high:
+      spawn greet(people[i][])
+  for i, p in people:
+    countB[i] = getRefCount(p)
+
+  for i in 0 .. <20:
+    doAssert countA[i] == countB[i]
+  echo "Success"
+
+# ---
+
+when isMainModule:
+  setup()
+  update()