blob: ae02c16e5c63118fc5c3aa0089f3059b83e77220 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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
|