Skip to content

Commit f2f76d8

Browse files
authored
Mark the _state field as atomic and move to proper atomics instead of llvmcall (#55502)
1 parent 31d413e commit f2f76d8

File tree

5 files changed

+10
-17
lines changed

5 files changed

+10
-17
lines changed

base/task.jl

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -156,20 +156,10 @@ const task_state_runnable = UInt8(0)
156156
const task_state_done = UInt8(1)
157157
const task_state_failed = UInt8(2)
158158

159-
const _state_index = findfirst(==(:_state), fieldnames(Task))
160-
@eval function load_state_acquire(t)
161-
# TODO: Replace this by proper atomic operations when available
162-
@GC.preserve t llvmcall($("""
163-
%rv = load atomic i8, i8* %0 acquire, align 8
164-
ret i8 %rv
165-
"""), UInt8, Tuple{Ptr{UInt8}},
166-
Ptr{UInt8}(pointer_from_objref(t) + fieldoffset(Task, _state_index)))
167-
end
168-
169159
@inline function getproperty(t::Task, field::Symbol)
170160
if field === :state
171161
# TODO: this field name should be deprecated in 2.0
172-
st = load_state_acquire(t)
162+
st = @atomic :acquire t._state
173163
if st === task_state_runnable
174164
return :runnable
175165
elseif st === task_state_done
@@ -223,7 +213,7 @@ julia> istaskdone(b)
223213
true
224214
```
225215
"""
226-
istaskdone(t::Task) = load_state_acquire(t) !== task_state_runnable
216+
istaskdone(t::Task) = (@atomic :acquire t._state) !== task_state_runnable
227217

228218
"""
229219
istaskstarted(t::Task) -> Bool
@@ -267,7 +257,7 @@ true
267257
!!! compat "Julia 1.3"
268258
This function requires at least Julia 1.3.
269259
"""
270-
istaskfailed(t::Task) = (load_state_acquire(t) === task_state_failed)
260+
istaskfailed(t::Task) = ((@atomic :acquire t._state) === task_state_failed)
271261

272262
Threads.threadid(t::Task) = Int(ccall(:jl_get_task_tid, Int16, (Any,), t)+1)
273263
function Threads.threadpool(t::Task)

src/jltypes.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3662,6 +3662,8 @@ void jl_init_types(void) JL_GC_DISABLED
36623662
XX(task);
36633663
jl_value_t *listt = jl_new_struct(jl_uniontype_type, jl_task_type, jl_nothing_type);
36643664
jl_svecset(jl_task_type->types, 0, listt);
3665+
const static uint32_t task_atomicfields[1] = {0x00001000}; // Set fields 13 as atomic
3666+
jl_task_type->name->atomicfields = task_atomicfields;
36653667

36663668
tv = jl_svec2(tvar("A"), tvar("R"));
36673669
jl_opaque_closure_type = (jl_unionall_t*)jl_new_datatype(jl_symbol("OpaqueClosure"), core, jl_function_type, tv,

stdlib/Serialization/src/Serialization.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,11 +1570,11 @@ function deserialize(s::AbstractSerializer, ::Type{Task})
15701570
t.storage = deserialize(s)
15711571
state = deserialize(s)
15721572
if state === :runnable
1573-
t._state = Base.task_state_runnable
1573+
@atomic :release t._state = Base.task_state_runnable
15741574
elseif state === :done
1575-
t._state = Base.task_state_done
1575+
@atomic :release t._state = Base.task_state_done
15761576
elseif state === :failed
1577-
t._state = Base.task_state_failed
1577+
@atomic :release t._state = Base.task_state_failed
15781578
else
15791579
@assert false
15801580
end

test/channels.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ end
382382
"""error in running finalizer: ErrorException("task switch not allowed from inside gc finalizer")""", output))
383383
# test for invalid state in Workqueue during yield
384384
t = @async nothing
385-
t._state = 66
385+
@atomic t._state = 66
386386
newstderr = redirect_stderr()
387387
try
388388
errstream = @async read(newstderr[1], String)

test/core.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ for (T, c) in (
4242
(DataType, [:types, :layout]),
4343
(Core.Memory, []),
4444
(Core.GenericMemoryRef, []),
45+
(Task, [:_state])
4546
)
4647
@test Set((fieldname(T, i) for i in 1:fieldcount(T) if Base.isfieldatomic(T, i))) == Set(c)
4748
end

0 commit comments

Comments
 (0)