1
1
module Internals
2
2
3
- import StableTasks: @spawn , @spawnat , StableTask
3
+ import StableTasks: @spawn , @spawnat , StableTask, AtomicRef
4
+
5
+ Base. getindex (r:: AtomicRef ) = @atomic r. x
6
+ Base. setindex! (r:: AtomicRef{T} , x) where {T} = @atomic r. x = convert (T, x)
4
7
5
8
function Base. fetch (t:: StableTask{T} ) where {T}
6
9
fetch (t. t)
@@ -25,41 +28,58 @@ Base.schedule(t::StableTask) = (schedule(t.t); t)
25
28
Base. schedule (t, val; error= false ) = (schedule (t. t, val; error); t)
26
29
27
30
"""
28
- Similar to `Threads.@spawn` but type-stable. Creates a `Task` and schedules it to run on any available thread in the `:default` threadpool.
31
+ @spawn [:default|:interactive] expr
32
+
33
+ Similar to `Threads.@spawn` but type-stable. Creates a `Task` and schedules it to run on any available
34
+ thread in the specified threadpool (defaults to the `:default` threadpool).
29
35
"""
30
- macro spawn (ex)
36
+ macro spawn (args... )
37
+ tp = QuoteNode (:default )
38
+ na = length (args)
39
+ if na == 2
40
+ ttype, ex = args
41
+ if ttype isa QuoteNode
42
+ ttype = ttype. value
43
+ if ttype != = :interactive && ttype != = :default
44
+ throw (ArgumentError (" unsupported threadpool in StableTasks.@spawn: $ttype " ))
45
+ end
46
+ tp = QuoteNode (ttype)
47
+ else
48
+ tp = ttype
49
+ end
50
+ elseif na == 1
51
+ ex = args[1 ]
52
+ else
53
+ throw (ArgumentError (" wrong number of arguments in @spawn" ))
54
+ end
55
+
31
56
letargs = _lift_one_interp! (ex)
32
57
33
58
thunk = replace_linenums! (:(() -> ($ (esc (ex)))), __source__)
34
59
var = esc (Base. sync_varname) # This is for the @sync macro which sets a local variable whose name is
35
60
# the symbol bound to Base.sync_varname
36
61
# I asked on slack and this is apparently safe to consider a public API
37
- set_pool = if VERSION < v " 1.9"
38
- nothing
39
- else
40
- :(Threads. _spawn_set_thrpool (task, :default ))
41
- end
42
62
quote
43
63
let $ (letargs... )
44
64
f = $ thunk
45
65
T = Core. Compiler. return_type (f, Tuple{})
46
- ref = Ref {T} ()
66
+ ref = AtomicRef {T} ()
47
67
f_wrap = () -> (ref[] = f (); nothing )
48
68
task = Task (f_wrap)
49
69
task. sticky = false
50
- $ set_pool
70
+ Threads . _spawn_set_thrpool (task, $ ( esc (tp)))
51
71
if $ (Expr (:islocal , var))
52
72
put! ($ var, task) # Sync will set up a Channel, and we want our task to be in there.
53
73
end
54
74
schedule (task)
55
- StableTask (task, ref)
75
+ StableTask {T} (task, ref)
56
76
end
57
77
end
58
78
end
59
79
60
80
"""
61
81
Similar to `StableTasks.@spawn` but creates a **sticky** `Task` and schedules it to run on the thread with the given id (`thrdid`).
62
- The task is guaranteed to stay on this thread (it won't migrate to another thread).
82
+ The task is guaranteed to stay on this thread (it won't migrate to another thread).
63
83
"""
64
84
macro spawnat (thrdid, ex)
65
85
letargs = _lift_one_interp! (ex)
@@ -81,7 +101,7 @@ macro spawnat(thrdid, ex)
81
101
let $ (letargs... )
82
102
thunk = $ thunk
83
103
RT = Core. Compiler. return_type (thunk, Tuple{})
84
- ret = Ref {RT} ()
104
+ ret = AtomicRef {RT} ()
85
105
thunk_wrap = () -> (ret[] = thunk (); nothing )
86
106
local task = Task (thunk_wrap)
87
107
task. sticky = true
0 commit comments