diff options
Diffstat (limited to 'tests/parallel')
-rw-r--r-- | tests/parallel/nim.cfg | 1 | ||||
-rw-r--r-- | tests/parallel/tgc_unsafe2.nim | 39 | ||||
-rw-r--r-- | tests/parallel/tparfind.nim | 28 | ||||
-rw-r--r-- | tests/parallel/tptr_to_ref.nim | 71 | ||||
-rw-r--r-- | tests/parallel/treadafterwrite.nim | 2 | ||||
-rw-r--r-- | tests/parallel/tuseafterdef.nim | 4 | ||||
-rw-r--r-- | tests/parallel/twrong_refcounts.nim | 53 |
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() |