Skip to content

Do not deadlock when the device compiler exits during a module build (#1393) - #1394

Closed
pvelesko wants to merge 2 commits into
mainfrom
2026-07-28-pocl-exit-deadlock
Closed

Do not deadlock when the device compiler exits during a module build (#1393)#1394
pvelesko wants to merge 2 commits into
mainfrom
2026-07-28-pocl-exit-deadlock

Conversation

@pvelesko

Copy link
Copy Markdown
Collaborator

Fixes #1393. Device::getOrCreateModule() held DeviceVarMtx across the backend compile, so a driver calling std::exit() there ran the atexit handler on the same thread and deallocateDeviceVariables() blocked on the mutex the build still held. A thread local marker around the backend build lets CHIPUninitializeCallOnce skip teardown and log why, so the process exits with the compiler code instead of hanging.

Regression test added: it interposes clBuildProgram and zeModuleCreate so libCHIP dispatches into them, then forks and re execs so the parent bounds the child rather than burning the harness timeout. Before the fix it reports the deadlock after 45.8 s; after, it passes in 1.6 s. Skips cleanly where the interposer cannot fire.

Trade off worth noting: this path skips teardown, so the process exits with the compiler exit code and leaks whatever the runtime held. That is acceptable since the process is already dying, but it is deliberate rather than incidental.

Regression runs: dgpu opencl 1014/1014, dgpu level0 1045/1046, the single failure being TestStaticLibRDC which passes standalone in 75.9 s and timed out only under concurrent load.

Upstream causes are filed separately at pocl/pocl#2258 and KhronosGroup/SPIRV-LLVM-Translator#3939.

pvelesko added 2 commits July 28, 2026 13:41
A backend compiler that ends the process with exit() instead of reporting
a rejected module (PoCL does this when the SPIR-V module needs an
extension the target lacks, e.g. SPV_INTEL_function_pointers) makes
chipStar hang: exit() runs the atexit handler on the same thread, which
re-enters Device::DeviceVarMtx that Device::getOrCreateModule() is still
holding across the build.

The test interposes clBuildProgram and zeModuleCreate so the failure is
reproduced without a driver that rejects the module, and bounds itself so
it reports FAIL instead of burning the harness timeout.
…uild

Device::getOrCreateModule() holds DeviceVarMtx across the backend compile.
PoCL ends the process with exit() there when its SPIR-V reader rejects a
module, for instance one that needs SPV_INTEL_function_pointers on a
target without it. exit() runs chipStar's atexit handler on the same
thread, and Device::deallocateDeviceVariables() then blocks forever on
the lock the build still holds, so the process wedges with no diagnostic.

Mark the module build region per thread and have CHIPUninitializeCallOnce()
skip teardown when it is entered from inside one, reporting what happened.
The rejected module now fails immediately with an explanation instead of
hanging until the harness times out.
@pvelesko

Copy link
Copy Markdown
Collaborator Author

Duplicate of #1389, which fixes the same self-deadlock in 5 lines by making DeviceVarMtx recursive. That is the better fix: teardown proceeds normally instead of being skipped. Closing in favour of it.

@pvelesko pvelesko closed this Jul 29, 2026
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.

Runtime deadlocks in its own exit handler when the device compiler calls exit() during a module build

1 participant