summary refs log tree commit diff stats
path: root/tests/parallel/tptr_to_ref.nim
diff options
context:
space:
mode:
Diffstat (limited to 'tests/parallel/tptr_to_ref.nim')
-rw-r--r--tests/parallel/tptr_to_ref.nim71
1 files changed, 71 insertions, 0 deletions
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