mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-14 19:27:01 -04:00
A render still running on a worker thread while the process exits crashes in the driver (SIGSEGV in the NVIDIA Vulkan driver on Linux), where neither the panic hook nor catch_unwind helps: pool workers were detached, the devices are statics that are never dropped, and nothing on the way out waited for GPU work. - gpu: every entry into a device (render, device creation, pool trim, denoise runner and tiles) is counted as work in flight (exit.rs). begin_shutdown() lets nothing new in; wait_idle(timeout) waits for what is inside. - preview: JobPool keeps its workers. shutdown(timeout) and Drop discard the queued jobs and wait, bounded, for the running ones (2 s on drop); never for the calling thread, and not twice. - engine: a render job caught by the shutdown gives up instead of rendering on the CPU, so quitting doesn't wait for it. - app: on_exit ends with LightcraftApp::shutdown (2 s for everything), after settings and library are saved; the macOS menu-bar Quit goes through on_exit. Not changed: the export, merge, denoise and import threads are still detached; their GPU work goes through the gate, their CPU work is cut off at exit as before. Tests: pool drop waits / is bounded / survives a panicked job and its own job dropping it; the gate; GPU renders refused and the device not created after begin_shutdown; the app's shutdown leaves no render worker. The crash itself needs Linux + NVIDIA and was not reproduced here (Windows, DX12): 9 of 9 quits of the app mid-render exit with code 0 in under 0.8 s. Co-Authored-By: Claude Opus 5.5 <[email protected]>
26 lines
1.3 KiB
Rust
26 lines
1.3 KiB
Rust
//! Issue #620: quitting right after the start must not leave the device being created (a long
|
|
//! call into the driver, on the `lc-gpu-init` thread) while the process exits. Once
|
|
//! `begin_shutdown` is called the device is not created at all.
|
|
//! One test in its own process: the shutdown comes before the first use of the GPU.
|
|
|
|
use std::sync::Arc;
|
|
use std::time::Duration;
|
|
|
|
use lightcraft_develop::DevelopSettings;
|
|
use lightcraft_pipeline::{RenderRequest, SourceInfo};
|
|
|
|
#[test]
|
|
fn the_device_is_not_created_once_the_process_is_ending() {
|
|
lightcraft_gpu::begin_shutdown();
|
|
lightcraft_gpu::warm_up();
|
|
assert!(!lightcraft_gpu::available());
|
|
assert_eq!(lightcraft_gpu::adapter_name(), None);
|
|
let src = Arc::new(lightcraft_scenes::demo_library()[0].render(300, 200));
|
|
let rendered = lightcraft_gpu::render(&src, &SourceInfo::default(), &DevelopSettings::default(), &RenderRequest::fit(300, 200), None);
|
|
assert!(rendered.is_none());
|
|
assert!(lightcraft_gpu::wait_idle(Duration::from_secs(60)), "the warm-up thread found the gate closed");
|
|
// `ready()` is "device creation finished" (or the GPU is switched off by the environment)
|
|
let switched_off = lightcraft_gpu::unavailable_reason().is_some_and(|r| r.starts_with("disabled by LIGHTCRAFT_GPU"));
|
|
assert!(switched_off || !lightcraft_gpu::ready(), "no device was created");
|
|
}
|