Give Windows a free-space gate, and stop two tests timing the scheduler

Three release-profile failures on macOS and Windows, all found by the qa gate
on its first run. Release-profile tests on those platforms had never run
before it existed, so none of these were regressions — they had simply never
been visible.

available_space returned None on every non-unix target. That did not merely
skip a test, it skipped the GATE: a Windows user extracting a disc to a full
volume got a confusing failure part-way through instead of a clear refusal up
front, and Windows is where the GUI ships. GetDiskFreeSpaceExW is declared
directly against kernel32, matching how scsi::windows already reaches Win32
rather than pulling in a binding crate for one call. It asks for
FreeBytesAvailableToCaller, which accounts for per-user quotas — the same
question f_bavail answers on unix.

The other two asserted on wall-clock timing with no margin:

- sleep_until_halted_wakes_mid_sleep bounded the wait at 350 ms and measured
  377 ms on a loaded runner. That bound measures the scheduler, not the wake.
  What the test is for is distinguishing "woke because the flag flipped" from
  "woke because the 10 s timeout expired", and 2 s does that just as well.

- abandon_loses_to_a_close_already_committed released at 600 ms against two
  300 ms grace windows plus a 250 ms poll cadence, so the windows could expire
  first and the caller abandoned — a race, not a defect. The intervals are
  scaled up so jitter is small relative to them; the ordering under test is
  unchanged, only the margin.
This commit is contained in:
Matthew Jackson
2026-08-05 21:20:29 -07:00
parent d0393fb629
commit 93ad1f4854
3 changed files with 73 additions and 5 deletions
+47 -1
View File
@@ -684,7 +684,53 @@ fn available_space(dir: &Path) -> Option<u64> {
Some(avail)
}
#[cfg(not(unix))]
/// Windows has no `statvfs`. This returned `None` unconditionally, which does
/// not merely skip a test — it skipped the free-space GATE, so a Windows user
/// extracting a disc to a full volume got a confusing failure part-way through
/// instead of a clear refusal up front. libfreemkv ships a Windows GUI, so that
/// is the platform where the friendly error matters most.
///
/// `GetDiskFreeSpaceExW` is declared directly against kernel32, matching how
/// `scsi::windows` already reaches the Win32 API rather than pulling in a
/// binding crate for one call.
#[cfg(windows)]
fn available_space(dir: &Path) -> Option<u64> {
use std::os::windows::ffi::OsStrExt;
unsafe extern "system" {
fn GetDiskFreeSpaceExW(
lpDirectoryName: *const u16,
lpFreeBytesAvailableToCaller: *mut u64,
lpTotalNumberOfBytes: *mut u64,
lpTotalNumberOfFreeBytes: *mut u64,
) -> i32;
}
// Wide, NUL-terminated. An interior NUL cannot reach the API, so reject it
// rather than silently truncating the path and measuring the wrong volume.
let mut wide: Vec<u16> = dir.as_os_str().encode_wide().collect();
if wide.contains(&0) {
return None;
}
wide.push(0);
let mut avail: u64 = 0;
// FreeBytesAvailableToCaller, not TotalNumberOfFreeBytes: it accounts for
// per-user quotas, which is what "can I actually write this much" means and
// what `statvfs`'s `f_bavail` gives on the unix side.
let ok = unsafe {
GetDiskFreeSpaceExW(
wide.as_ptr(),
&mut avail,
std::ptr::null_mut(),
std::ptr::null_mut(),
)
};
if ok == 0 { None } else { Some(avail) }
}
/// Neither unix nor Windows: no way to ask, so the gate is skipped.
#[cfg(not(any(unix, windows)))]
fn available_space(_dir: &Path) -> Option<u64> {
None
}