Skip to content

Commit

Permalink
fixup! threads: avoid deadlock from recursive lock acquire
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Nov 30, 2020
1 parent 3ea5447 commit b048f7b
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 15 deletions.
1 change: 1 addition & 0 deletions base/locks-mt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ function trylock(l::SpinLock)
end

function unlock(l::SpinLock)
_get(l) == 0 && error("unlock count must match lock count")
_set!(l, 0)
GC.enable_finalizers(true)
ccall(:jl_cpu_wake, Cvoid, ())
Expand Down
7 changes: 6 additions & 1 deletion src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,12 @@ JL_DLLEXPORT void jl_gc_enable_finalizers(jl_ptls_t ptls, int on)
}
JL_CATCH {
jl_printf((JL_STREAM*)STDERR_FILENO, "WARNING: GC finalizers already enabled on this thread. Possibly unpaired within a try block?\n");
jlbacktrace(); // written to STDERR_FILENO
// Only print the backtrace once, to avoid spamming the logs
static int backtrace_printed = 0;
if (backtrace_printed == 0) {
backtrace_printed = 1;
jlbacktrace(); // written to STDERR_FILENO
}
}
return;
}
Expand Down
2 changes: 1 addition & 1 deletion test/misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ end
# Debugging tool: return the current state of the enable_finalizers counter.
enable_finalizers_count() = ccall(:jl_gc_get_enable_finalizers, Int32, (Ptr{Cvoid},), C_NULL)

let l = ReentrantLock()
for l in (Threads.SpinLock(), ReentrantLock())
@test enable_finalizers_count() == 0
@test lock(enable_finalizers_count, l) == 1
@test enable_finalizers_count() == 0
Expand Down
26 changes: 13 additions & 13 deletions test/threads_exec.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ test_threaded_atomic_minmax(UInt16(27000),UInt16(37000))
function threaded_add_locked(::Type{LockT}, x, n) where LockT
critical = LockT()
@threads for i = 1:n
@test lock(critical) === nothing
lock(critical)
@test islocked(critical)
x = x + 1
@test unlock(critical) === nothing
unlock(critical)
end
@test !islocked(critical)
nentered = 0
Expand All @@ -124,7 +124,7 @@ function threaded_add_locked(::Type{LockT}, x, n) where LockT
if trylock(critical)
@test islocked(critical)
nentered += 1
@test unlock(critical) === nothing
unlock(critical)
else
atomic_add!(nfailed, 1)
end
Expand All @@ -142,21 +142,21 @@ end
let critical = ReentrantLock()
@test !islocked(critical)
@test_throws ErrorException("unlock count must match lock count") unlock(critical)
@test lock(critical) === nothing
lock(critical)
@test islocked(critical)
@test lock(critical) === nothing
@test trylock(critical) == true
lock(critical)
t = trylock(critical); @test t
@test islocked(critical)
@test unlock(critical) === nothing
unlock(critical)
@test islocked(critical)
@test unlock(critical) === nothing
unlock(critical)
@test islocked(critical)
@test unlock(critical) === nothing
unlock(critical)
@test !islocked(critical)
@test_throws ErrorException("unlock count must match lock count") unlock(critical)
@test trylock(critical) == true
t = trylock(critical); @test t
@test islocked(critical)
@test unlock(critical) === nothing
unlock(critical)
@test !islocked(critical)
@test_throws ErrorException("unlock count must match lock count") unlock(critical)
@test !islocked(critical)
Expand All @@ -167,10 +167,10 @@ end
function threaded_gc_locked(::Type{LockT}) where LockT
critical = LockT()
@threads for i = 1:20
@test lock(critical) === nothing
lock(critical)
@test islocked(critical)
GC.gc(false)
@test unlock(critical) === nothing
unlock(critical)
end
@test !islocked(critical)
end
Expand Down

0 comments on commit b048f7b

Please sign in to comment.