Skip to content

Commit

Permalink
Fix thread safety in atexit(f): Lock access to atexit_hooks (JuliaL…
Browse files Browse the repository at this point in the history
…ang#49774)

- atexit(f) mutates global shared state.
- atexit(f) can be called anytime by any thread.
- Accesses & mutations to global shared state must be locked if they can
  be accessed from multiple threads.

Add unit test for thread safety of adding many atexit functions in
parallel
  • Loading branch information
NHDaly authored and kpamnany committed May 24, 2023
1 parent e38fa95 commit f416923
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 1 deletion.
3 changes: 2 additions & 1 deletion base/initdefs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ end
const atexit_hooks = Callable[
() -> Filesystem.temp_cleanup_purge(force=true)
]
const _atexit_hooks_lock = ReentrantLock()

"""
atexit(f)
Expand All @@ -374,7 +375,7 @@ calls `exit(n)`, then Julia will exit with the exit code corresponding to the
last called exit hook that calls `exit(n)`. (Because exit hooks are called in
LIFO order, "last called" is equivalent to "first registered".)
"""
atexit(f::Function) = (pushfirst!(atexit_hooks, f); nothing)
atexit(f::Function) = Base.@lock _atexit_hooks_lock (pushfirst!(atexit_hooks, f); nothing)

function _atexit(exitcode::Cint)
while !isempty(atexit_hooks)
Expand Down
20 changes: 20 additions & 0 deletions test/threads_exec.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1067,3 +1067,23 @@ end
popfirst!(LOAD_PATH)
end
end

# issue #49746, thread safety in `atexit(f)`
@testset "atexit thread safety" begin
f = () -> nothing
before_len = length(Base.atexit_hooks)
@sync begin
for _ in 1:1_000_000
Threads.@spawn begin
atexit(f)
end
end
end
@test length(Base.atexit_hooks) == before_len + 1_000_000
@test all(hook -> hook === f, Base.atexit_hooks[1 : 1_000_000])

# cleanup
Base.@lock Base._atexit_hooks_lock begin
deleteat!(Base.atexit_hooks, 1:1_000_000)
end
end

0 comments on commit f416923

Please sign in to comment.