diff --git a/crates/gpu/src/backend.rs b/crates/gpu/src/backend.rs index 57e47f22e..d970003e7 100644 --- a/crates/gpu/src/backend.rs +++ b/crates/gpu/src/backend.rs @@ -213,12 +213,12 @@ fn disarm(marker: &std::path::Path, active: &Mutex) { } /// Removes the marker on the way out, a panic included (the process survived). -struct Armed(Option); +struct Armed<'a>(Option, &'a Mutex); -impl Drop for Armed { +impl Drop for Armed<'_> { fn drop(&mut self) { if let Some(m) = &self.0 { - disarm(m, &ACTIVE); + disarm(m, self.1); } } } @@ -227,10 +227,16 @@ impl Drop for Armed { /// removing the init marker (if one is set). pub(crate) fn with_marker(what: &str, f: impl FnOnce() -> T) -> T { let marker = MARKER.lock().unwrap_or_else(|e| e.into_inner()).clone(); + with_marker_on(marker, &ACTIVE, what, f) +} + +/// [`with_marker`] on an explicit marker path and scope counter (the tests use their own, so that +/// device-creating tests running in parallel cannot join their scopes). +fn with_marker_on(marker: Option, active: &Mutex, what: &str, f: impl FnOnce() -> T) -> T { if let Some(m) = &marker { - arm(m, &ACTIVE, what); + arm(m, active, what); } - let _armed = Armed(marker); + let _armed = Armed(marker, active); f() } @@ -352,9 +358,6 @@ mod tests { } use super::*; - /// The tests that set the process-wide marker take turns. - static GLOBAL: Mutex<()> = Mutex::new(()); - #[test] fn parses_backend_names() { assert_eq!(parse_backends("dx12"), Some(BackendChoice::Use(Backends::DX12))); @@ -421,13 +424,12 @@ mod tests { #[test] fn init_marker_is_written_during_creation_and_removed_after() { - let _turn = GLOBAL.lock().unwrap_or_else(|e| e.into_inner()); let dir = std::env::temp_dir().join(format!("lc-gpu-marker-{}", std::process::id())); let m = dir.join("gpu-init.marker"); let _ = std::fs::remove_dir_all(&dir); - set_init_marker(Some(m.clone())); - let seen = with_init_marker(Backends::DX12, || m.exists()); - set_init_marker(None); + // a local scope counter: other tests create real devices through the process-wide one + let active = Mutex::new(0); + let seen = with_marker_on(Some(m.clone()), &active, "device creation", || m.exists()); assert!(seen, "the marker exists while the device is created"); assert!(!m.exists(), "and is removed afterwards"); // a marker left behind by a crashed process is reported once; reading it leaves it in place @@ -440,6 +442,20 @@ mod tests { let _ = std::fs::remove_dir_all(&dir); } + #[test] + fn with_init_marker_writes_the_process_wide_marker() { + let dir = std::env::temp_dir().join(format!("lc-gpu-global-{}", std::process::id())); + let m = dir.join("gpu-init.marker"); + let _ = std::fs::remove_dir_all(&dir); + set_init_marker(Some(m.clone())); + let seen = with_init_marker(Backends::DX12, || m.exists()); + set_init_marker(None); + // not checked for removal: device-creating tests running in parallel may still hold the file + // (the test above checks removal on its own scope counter) + assert!(seen, "the marker set with set_init_marker exists while the device is created"); + let _ = std::fs::remove_dir_all(&dir); + } + /// The window's renderer fallback: forced, remembered, the platform chain, the failed one last. #[test] fn window_renderer_fallback_order() { @@ -505,13 +521,11 @@ mod tests { #[test] fn a_panic_inside_the_scope_still_removes_the_marker() { - let _turn = GLOBAL.lock().unwrap_or_else(|e| e.into_inner()); let dir = std::env::temp_dir().join(format!("lc-gpu-panic-{}", std::process::id())); let m = dir.join("gpu-init.marker"); let _ = std::fs::remove_dir_all(&dir); - set_init_marker(Some(m.clone())); - let r = std::panic::catch_unwind(|| with_marker("kernel compilation", || panic!("compile"))); - set_init_marker(None); + let active = Mutex::new(0); + let r = std::panic::catch_unwind(|| with_marker_on(Some(m.clone()), &active, "kernel compilation", || panic!("compile"))); assert!(r.is_err()); assert!(!m.exists(), "the process survived, so nothing is left to report"); let _ = std::fs::remove_dir_all(&dir);