Skip to content

Commit 3847ff1

Browse files
authored
Replace Base.Workqueues with a OncePerThread (JuliaLang#58941)
Simplify `workqueue_for`. While not strictly necessary, the acquire load in `getindex(once::OncePerThread{T,F}, tid::Integer)` makes ThreadSanitizer happy. With the existing implementation, we get false positives whenever a thread other than the one that originally allocated the array reads it: ``` ================== WARNING: ThreadSanitizer: data race (pid=6819) Atomic read of size 8 at 0xffff86bec058 by main thread: #0 getproperty Base_compiler.jl:57 (sys.so+0x113b478) #1 julia_pushNOT._1925 task.jl:868 (sys.so+0x113b478) mmtk#2 julia_enq_work_1896 task.jl:969 (sys.so+0x5cd218) mmtk#3 schedule task.jl:983 (sys.so+0x892294) mmtk#4 macro expansion threadingconstructs.jl:522 (sys.so+0x892294) mmtk#5 julia_start_profile_listener_60681 Base.jl:355 (sys.so+0x892294) mmtk#6 julia___init___60641 Base.jl:392 (sys.so+0x1178dc) mmtk#7 jfptr___init___60642 <null> (sys.so+0x118134) mmtk#8 _jl_invoke /home/user/c/julia/src/gf.c (libjulia-internal.so.1.13+0x5e9a4) mmtk#9 ijl_apply_generic /home/user/c/julia/src/gf.c:3892:12 (libjulia-internal.so.1.13+0x5e9a4) mmtk#10 jl_apply /home/user/c/julia/src/julia.h:2343:12 (libjulia-internal.so.1.13+0xbba74) mmtk#11 jl_module_run_initializer /home/user/c/julia/src/toplevel.c:68:13 (libjulia-internal.so.1.13+0xbba74) mmtk#12 _finish_jl_init_ /home/user/c/julia/src/init.c:632:13 (libjulia-internal.so.1.13+0x9c0fc) mmtk#13 ijl_init_ /home/user/c/julia/src/init.c:783:5 (libjulia-internal.so.1.13+0x9bcf4) mmtk#14 jl_repl_entrypoint /home/user/c/julia/src/jlapi.c:1125:5 (libjulia-internal.so.1.13+0xf7ec8) mmtk#15 jl_load_repl /home/user/c/julia/cli/loader_lib.c:601:12 (libjulia.so.1.13+0x11934) mmtk#16 main /home/user/c/julia/cli/loader_exe.c:58:15 (julia+0x10dc20) Previous write of size 8 at 0xffff86bec058 by thread T2: #0 IntrusiveLinkedListSynchronized task.jl:863 (sys.so+0x78d220) #1 macro expansion task.jl:932 (sys.so+0x78d220) mmtk#2 macro expansion lock.jl:376 (sys.so+0x78d220) mmtk#3 julia_workqueue_for_1933 task.jl:924 (sys.so+0x78d220) mmtk#4 julia_wait_2048 task.jl:1204 (sys.so+0x6255ac) mmtk#5 julia_task_done_hook_49205 task.jl:839 (sys.so+0x128fdc0) mmtk#6 jfptr_task_done_hook_49206 <null> (sys.so+0x902218) mmtk#7 _jl_invoke /home/user/c/julia/src/gf.c (libjulia-internal.so.1.13+0x5e9a4) mmtk#8 ijl_apply_generic /home/user/c/julia/src/gf.c:3892:12 (libjulia-internal.so.1.13+0x5e9a4) mmtk#9 jl_apply /home/user/c/julia/src/julia.h:2343:12 (libjulia-internal.so.1.13+0x9c79c) mmtk#10 jl_finish_task /home/user/c/julia/src/task.c:345:13 (libjulia-internal.so.1.13+0x9c79c) mmtk#11 jl_threadfun /home/user/c/julia/src/scheduler.c:122:5 (libjulia-internal.so.1.13+0xe7db8) Thread T2 (tid=6824, running) created by main thread at: #0 pthread_create <null> (julia+0x85f88) #1 uv_thread_create_ex /workspace/srcdir/libuv/src/unix/thread.c:172 (libjulia-internal.so.1.13+0x1a8d70) mmtk#2 _finish_jl_init_ /home/user/c/julia/src/init.c:618:5 (libjulia-internal.so.1.13+0x9c010) mmtk#3 ijl_init_ /home/user/c/julia/src/init.c:783:5 (libjulia-internal.so.1.13+0x9bcf4) mmtk#4 jl_repl_entrypoint /home/user/c/julia/src/jlapi.c:1125:5 (libjulia-internal.so.1.13+0xf7ec8) mmtk#5 jl_load_repl /home/user/c/julia/cli/loader_lib.c:601:12 (libjulia.so.1.13+0x11934) mmtk#6 main /home/user/c/julia/cli/loader_exe.c:58:15 (julia+0x10dc20) SUMMARY: ThreadSanitizer: data race Base_compiler.jl:57 in getproperty ================== ```
1 parent f837bf0 commit 3847ff1

File tree

1 file changed

+2
-23
lines changed

1 file changed

+2
-23
lines changed

base/task.jl

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -909,31 +909,10 @@ function list_deletefirst!(W::IntrusiveLinkedListSynchronized{T}, t::T) where T
909909
end
910910

911911
const StickyWorkqueue = IntrusiveLinkedListSynchronized{Task}
912-
global Workqueues::Vector{StickyWorkqueue} = [StickyWorkqueue()]
913-
const Workqueues_lock = Threads.SpinLock()
912+
const Workqueues = OncePerThread{StickyWorkqueue}(StickyWorkqueue)
914913
const Workqueue = Workqueues[1] # default work queue is thread 1 // TODO: deprecate this variable
915914

916-
function workqueue_for(tid::Int)
917-
qs = Workqueues
918-
if length(qs) >= tid && isassigned(qs, tid)
919-
return @inbounds qs[tid]
920-
end
921-
# slow path to allocate it
922-
@assert tid > 0
923-
l = Workqueues_lock
924-
@lock l begin
925-
qs = Workqueues
926-
if length(qs) < tid
927-
nt = Threads.maxthreadid()
928-
@assert tid <= nt
929-
global Workqueues = qs = copyto!(typeof(qs)(undef, length(qs) + nt - 1), qs)
930-
end
931-
if !isassigned(qs, tid)
932-
@inbounds qs[tid] = StickyWorkqueue()
933-
end
934-
return @inbounds qs[tid]
935-
end
936-
end
915+
workqueue_for(tid::Int) = Workqueues[tid]
937916

938917
function enq_work(t::Task)
939918
(t._state === task_state_runnable && t.queue === nothing) || error("schedule: Task not runnable")

0 commit comments

Comments
 (0)