Skip to content

Commit f28c6d8

Browse files
committed
Temporary fix to make sure GC while holding a lock will not dead lock.
Add tests.
1 parent 971b759 commit f28c6d8

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

base/locks.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ function lock!(l::TatasLock)
2323
end
2424
end
2525
ccall(:jl_cpu_pause, Void, ())
26+
# Temporary solution before we have gc transition support in codegen.
27+
# This could mess up gc state when we add codegen support.
28+
# Use these as a safe point
29+
gc_state = ccall(:jl_gc_safe_enter, Int8, ())
30+
ccall(:jl_gc_safe_leave, Void, (Int8,), gc_state)
2631
end
2732
end
2833

@@ -61,6 +66,11 @@ function lock!(l::RecursiveTatasLock)
6166
end
6267
end
6368
ccall(:jl_cpu_pause, Void, ())
69+
# Temporary solution before we have gc transition support in codegen.
70+
# This could mess up gc state when we add codegen support.
71+
# Use these as a safe point
72+
gc_state = ccall(:jl_gc_safe_enter, Int8, ())
73+
ccall(:jl_gc_safe_leave, Void, (Int8,), gc_state)
6474
end
6575
end
6676

@@ -116,7 +126,11 @@ function lock!(m::Mutex)
116126
if m.ownertid == threadid()
117127
return 0
118128
end
129+
# Temporary solution before we have gc transition support in codegen.
130+
# This could mess up gc state when we add codegen support.
131+
gc_state = ccall(:jl_gc_safe_enter, Int8, ())
119132
ccall(:uv_mutex_lock, Void, (Ptr{Void},), m.handle)
133+
ccall(:jl_gc_safe_leave, Void, (Int8,), gc_state)
120134
m.ownertid = threadid()
121135
return 0
122136
end

src/jlapi.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,16 @@ JL_DLLEXPORT void (jl_gc_unsafe_leave)(int8_t state)
328328
jl_gc_unsafe_leave(state);
329329
}
330330

331+
JL_DLLEXPORT int8_t (jl_gc_safe_enter)(void)
332+
{
333+
return jl_gc_state_save_and_set(3);
334+
}
335+
336+
JL_DLLEXPORT void (jl_gc_safe_leave)(int8_t state)
337+
{
338+
jl_gc_state_set(state, 3);
339+
}
340+
331341
#ifdef __cplusplus
332342
}
333343
#endif

test/threads.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,18 @@ let lock = Threads.RecursiveSpinLock()
8383
@test unlock!(lock) == 0
8484
@test unlock!(lock) == 1
8585
end
86+
87+
# Make sure doing a GC while holding a lock doesn't cause dead lock
88+
# PR 14190. (This is only meaningful for threading)
89+
function threaded_gc_locked{LockT}(::Type{LockT})
90+
lock = LockT()
91+
@threads for i = 1:20
92+
lock!(lock)
93+
gc(false)
94+
unlock!(lock)
95+
end
96+
end
97+
98+
threaded_gc_locked(SpinLock)
99+
threaded_gc_locked(Threads.RecursiveSpinLock)
100+
threaded_gc_locked(Mutex)

0 commit comments

Comments
 (0)