diff options
-rw-r--r-- | tests/parallel/tptr_to_ref.nim | 53 |
1 files changed, 49 insertions, 4 deletions
diff --git a/tests/parallel/tptr_to_ref.nim b/tests/parallel/tptr_to_ref.nim index 66d618481..229c247ce 100644 --- a/tests/parallel/tptr_to_ref.nim +++ b/tests/parallel/tptr_to_ref.nim @@ -1,21 +1,26 @@ # 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 = 10 +const MAX_WORKERS = 50 type - Killer = object - lock: Lock - bailed {.guard: lock.}: bool + 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: @@ -23,4 +28,44 @@ proc initKiller*(): Killer = 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 |