Skip to content

Commit 6b926f3

Browse files
xal-0KristofferC
authored andcommitted
Fix windows profiler deadlock (#60056)
Wasn't sure if we could get away with deleting the `uv_thread_detach`, but apparently we can. On Windows, it's definitely unsafe to keep using the thread handle after closing it. POSIX is a little less clear about what you're allowed to do with a `pthread_t` after detaching it, but the GC threads never exit normally anyway. Fixes #60042. (cherry picked from commit d8b5662)
1 parent 8dc57e1 commit 6b926f3

File tree

3 files changed

+33
-14
lines changed

3 files changed

+33
-14
lines changed

src/gc-stock.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3612,7 +3612,6 @@ void jl_start_gc_threads(void)
36123612
else {
36133613
uv_thread_create(&uvtid, jl_parallel_gc_threadfun, t);
36143614
}
3615-
uv_thread_detach(&uvtid);
36163615
}
36173616
}
36183617

src/signals-win.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ static int jl_thread_suspend_and_get_state(int tid, int timeout, bt_context_t *c
445445
if (ct2 == NULL) // this thread is already dead
446446
return 0;
447447
HANDLE hThread = ptls2->system_id;
448+
assert(GetCurrentThreadId() != GetThreadId(hThread));
448449
if ((DWORD)-1 == SuspendThread(hThread)) {
449450
// jl_safe_fprintf(ios_safe_stderr, "failed to suspend thread %d: %lu\n", tid, GetLastError());
450451
return 0;

stdlib/Profile/test/runtests.jl

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,23 @@ end
246246
@test occursin("@julialib" * slash, str)
247247
end
248248

249+
function run_with_watchdog(cmd, timeout=120)
250+
p = open(cmd)
251+
t = Timer(timeout) do t
252+
# should be under 10 seconds, so give it 2 minutes then report failure
253+
println("KILLING debuginfo registration test BY PROFILE TEST WATCHDOG\n")
254+
kill(p, Base.SIGQUIT)
255+
sleep(30)
256+
kill(p, Base.SIGQUIT)
257+
sleep(30)
258+
kill(p, Base.SIGKILL)
259+
end
260+
s = read(p, String)
261+
close(t)
262+
close(p)
263+
success(p) ? s : ""
264+
end
265+
249266
# Profile deadlocking in compilation (debuginfo registration)
250267
let cmd = Base.julia_cmd()
251268
script = """
@@ -259,24 +276,26 @@ let cmd = Base.julia_cmd()
259276
print(Profile.len_data())
260277
"""
261278
# use multiple threads here to ensure that profiling works with threading
262-
p = open(`$cmd -t2 -e $script`)
263-
t = Timer(120) do t
264-
# should be under 10 seconds, so give it 2 minutes then report failure
265-
println("KILLING debuginfo registration test BY PROFILE TEST WATCHDOG\n")
266-
kill(p, Base.SIGQUIT)
267-
sleep(30)
268-
kill(p, Base.SIGQUIT)
269-
sleep(30)
270-
kill(p, Base.SIGKILL)
271-
end
272-
s = read(p, String)
273-
close(t)
274-
@test success(p)
279+
s = run_with_watchdog(`$cmd -t2 -e $script`)
275280
@test !isempty(s)
276281
@test occursin("done", s)
277282
@test parse(Int, split(s, '\n')[end]) > 100
278283
end
279284

285+
# Thread suspend deadlock - run many times (#60042)
286+
let cmd = Base.julia_cmd()
287+
script = """
288+
using Profile
289+
@profile println("done")
290+
"""
291+
good = true
292+
for i=1:100
293+
s = run_with_watchdog(`$cmd -t2 -e $script`, 5)
294+
good &= occursin("done", s)
295+
end
296+
@test good
297+
end
298+
280299
if Sys.isbsd() || Sys.islinux()
281300
@testset "SIGINFO/SIGUSR1 profile triggering" begin
282301
let cmd = Base.julia_cmd()

0 commit comments

Comments
 (0)