Skip to content

Test multithreaded GC with NEO's SIGSEGV handler installed - #706

Merged
maleadt merged 1 commit into
mainfrom
tb/neo-sigsegv-chaining
Oct 18, 2026
Merged

maleadt merged 1 commit into
mainfrom
tb/neo-sigsegv-chaining

Conversation

@maleadt

@maleadt maleadt commented Oct 16, 2026

Copy link
Copy Markdown
Member

NEO installs a SIGSEGV handler that forwards faults it doesn't own to Julia's, tracking its position in the handler chain with a counter shared by all threads. Julia's GC makes every thread fault on the safepoint page at the same time, so with more than one thread a GC crashed the process with a bare SIGSEGV. NEO_jll 26.35.39758+1 (JuliaPackaging/Yggdrasil#15164) makes that counter thread-local; the fix is proposed upstream in intel/compute-runtime#1009.

The test runs a 4-thread GC loop in a child process. NEO only installs its handler for shared allocations with device storage, which integrated GPUs don't use, so the test forces that with NEO debug keys; on the TGL runner the allocation then fails, but the handler is installed. With NEO_jll +0 the child dies from SIGSEGV 5/5 times, with +1 it passes 5/5.

The test is skipped when NEO_jll's libze_intel_gpu is redirected outside its artifact, as on Aurora, where the system driver doesn't have the fix yet.

Fixes #607.

NEO chains its SIGSEGV handler to Julia's using a counter shared by all
threads, so Julia's GC, which makes every thread fault on the safepoint
page at once, crashed the process. NEO_jll 26.35.39758+1 carries the fix
(intel/compute-runtime#1009). The test forces NEO to install its handler
on integrated GPUs as well, through debug keys, and is skipped when
NEO_jll is pointed at a system driver, as on Aurora.

Fixes #607.
@github-actions

Copy link
Copy Markdown
Contributor

Your PR requires formatting changes to meet the project's style guidelines.
Please consider running Runic (git runic main) to apply these changes.

Click here to view the suggested changes.
diff --git a/test/level-zero.jl b/test/level-zero.jl
index b86ed26..4b0a25d 100644
--- a/test/level-zero.jl
+++ b/test/level-zero.jl
@@ -391,30 +391,30 @@ end
 
 @testset "SIGSEGV handler chaining" begin
 
-# NEO installs a SIGSEGV handler that chains to Julia's. Julia's GC makes every thread fault
-# on its safepoint page at the same time, which crashed NEO before it made chaining
-# thread-safe (oneAPI.jl#607, intel/compute-runtime#1009).
-script = raw"""
-    using oneAPI, oneAPI.oneL0
-    # NEO installs its handler on the first shared allocation that gets device storage.
-    # Integrated GPUs normally don't use it, and fail the allocation when forced to,
-    # but the handler is installed anyway.
-    try
-        free(shared_alloc(context(), device(), 1024))
-    catch err
-        err isa oneL0.OutOfGPUMemoryError || rethrow()
-    end
-    Threads.@threads for i in 1:100
-        x = [rand(100) for _ in 1:1000]
-        GC.gc(false)
-    end
-"""
-cmd = `$(Base.julia_cmd()) --project=$(Base.active_project()) --threads=4 -e $script`
-cmd = addenv(cmd, "NEOReadDebugKeys" => "1", "AllocateSharedAllocationsWithCpuAndGpuStorage" => "1")
-# Only our NEO_jll build carries the fix; skip with a system driver (e.g. on Aurora, where
-# preferences point NEO_jll at /usr/lib64).
-NEO_jll = oneL0.NEO_jll
-system_driver = !startswith(NEO_jll.libze_intel_gpu, NEO_jll.artifact_dir)
-@test success(pipeline(cmd, stdout=stdout, stderr=stderr)) skip=system_driver
+    # NEO installs a SIGSEGV handler that chains to Julia's. Julia's GC makes every thread fault
+    # on its safepoint page at the same time, which crashed NEO before it made chaining
+    # thread-safe (oneAPI.jl#607, intel/compute-runtime#1009).
+    script = raw"""
+        using oneAPI, oneAPI.oneL0
+        # NEO installs its handler on the first shared allocation that gets device storage.
+        # Integrated GPUs normally don't use it, and fail the allocation when forced to,
+        # but the handler is installed anyway.
+        try
+            free(shared_alloc(context(), device(), 1024))
+        catch err
+            err isa oneL0.OutOfGPUMemoryError || rethrow()
+        end
+        Threads.@threads for i in 1:100
+            x = [rand(100) for _ in 1:1000]
+            GC.gc(false)
+        end
+    """
+    cmd = `$(Base.julia_cmd()) --project=$(Base.active_project()) --threads=4 -e $script`
+    cmd = addenv(cmd, "NEOReadDebugKeys" => "1", "AllocateSharedAllocationsWithCpuAndGpuStorage" => "1")
+    # Only our NEO_jll build carries the fix; skip with a system driver (e.g. on Aurora, where
+    # preferences point NEO_jll at /usr/lib64).
+    NEO_jll = oneL0.NEO_jll
+    system_driver = !startswith(NEO_jll.libze_intel_gpu, NEO_jll.artifact_dir)
+    @test success(pipeline(cmd, stdout = stdout, stderr = stderr)) skip = system_driver
 
 end

@codecov

codecov Bot commented Oct 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.44%. Comparing base (8460d3f) to head (13e0764).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #706      +/-   ##
==========================================
- Coverage   83.70%   83.44%   -0.26%     
==========================================
  Files          52       51       -1     
  Lines        4376     4253     -123     
==========================================
- Hits         3663     3549     -114     
+ Misses        713      704       -9     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@maleadt
maleadt merged commit 3d5ac7c into main Oct 18, 2026
5 checks passed
@maleadt
maleadt deleted the tb/neo-sigsegv-chaining branch October 18, 2026 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Segfault in multithreaded code: NEO SIGSEGV handler race (intel/compute-runtime#1009)

1 participant