Skip to content

Commit

Permalink
Mark the _state field as atomic and move to proper atomics instead of…
Browse files Browse the repository at this point in the history
… llvmcall (#55502)
  • Loading branch information
gbaraldi authored and KristofferC committed Sep 12, 2024
1 parent ed6d643 commit 4e8df58
Show file tree
Hide file tree
Showing 5 changed files with 10 additions and 17 deletions.
16 changes: 3 additions & 13 deletions base/task.jl
Original file line number Diff line number Diff line change
Expand Up @@ -156,20 +156,10 @@ const task_state_runnable = UInt8(0)
const task_state_done = UInt8(1)
const task_state_failed = UInt8(2)

const _state_index = findfirst(==(:_state), fieldnames(Task))
@eval function load_state_acquire(t)
# TODO: Replace this by proper atomic operations when available
@GC.preserve t llvmcall($("""
%rv = load atomic i8, i8* %0 acquire, align 8
ret i8 %rv
"""), UInt8, Tuple{Ptr{UInt8}},
Ptr{UInt8}(pointer_from_objref(t) + fieldoffset(Task, _state_index)))
end

@inline function getproperty(t::Task, field::Symbol)
if field === :state
# TODO: this field name should be deprecated in 2.0
st = load_state_acquire(t)
st = @atomic :acquire t._state
if st === task_state_runnable
return :runnable
elseif st === task_state_done
Expand Down Expand Up @@ -223,7 +213,7 @@ julia> istaskdone(b)
true
```
"""
istaskdone(t::Task) = load_state_acquire(t) !== task_state_runnable
istaskdone(t::Task) = (@atomic :acquire t._state) !== task_state_runnable

"""
istaskstarted(t::Task) -> Bool
Expand Down Expand Up @@ -267,7 +257,7 @@ true
!!! compat "Julia 1.3"
This function requires at least Julia 1.3.
"""
istaskfailed(t::Task) = (load_state_acquire(t) === task_state_failed)
istaskfailed(t::Task) = ((@atomic :acquire t._state) === task_state_failed)

Threads.threadid(t::Task) = Int(ccall(:jl_get_task_tid, Int16, (Any,), t)+1)
function Threads.threadpool(t::Task)
Expand Down
2 changes: 2 additions & 0 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -3662,6 +3662,8 @@ void jl_init_types(void) JL_GC_DISABLED
XX(task);
jl_value_t *listt = jl_new_struct(jl_uniontype_type, jl_task_type, jl_nothing_type);
jl_svecset(jl_task_type->types, 0, listt);
const static uint32_t task_atomicfields[1] = {0x00001000}; // Set fields 13 as atomic
jl_task_type->name->atomicfields = task_atomicfields;

tv = jl_svec2(tvar("A"), tvar("R"));
jl_opaque_closure_type = (jl_unionall_t*)jl_new_datatype(jl_symbol("OpaqueClosure"), core, jl_function_type, tv,
Expand Down
6 changes: 3 additions & 3 deletions stdlib/Serialization/src/Serialization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1570,11 +1570,11 @@ function deserialize(s::AbstractSerializer, ::Type{Task})
t.storage = deserialize(s)
state = deserialize(s)
if state === :runnable
t._state = Base.task_state_runnable
@atomic :release t._state = Base.task_state_runnable
elseif state === :done
t._state = Base.task_state_done
@atomic :release t._state = Base.task_state_done
elseif state === :failed
t._state = Base.task_state_failed
@atomic :release t._state = Base.task_state_failed
else
@assert false
end
Expand Down
2 changes: 1 addition & 1 deletion test/channels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ end
"""error in running finalizer: ErrorException("task switch not allowed from inside gc finalizer")""", output))
# test for invalid state in Workqueue during yield
t = @async nothing
t._state = 66
@atomic t._state = 66
newstderr = redirect_stderr()
try
errstream = @async read(newstderr[1], String)
Expand Down
1 change: 1 addition & 0 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ for (T, c) in (
(DataType, [:types, :layout]),
(Core.Memory, []),
(Core.GenericMemoryRef, []),
(Task, [:_state])
)
@test Set((fieldname(T, i) for i in 1:fieldcount(T) if Base.isfieldatomic(T, i))) == Set(c)
end
Expand Down

0 comments on commit 4e8df58

Please sign in to comment.