Skip to content

Commit ca69664

Browse files
committed
Wait for overlapped WriteFile completion in Rust (RustPython#7383)
On Windows, SimpleQueue skips write locking because pipe writes are assumed atomic. Without GIL, PipeConnection. _send_bytes races on _send_ov when multiple threads call send_bytes concurrently (e.g. _terminate_pool vs workers). Wait for pending overlapped writes inside WriteFile before returning to Python, so ERROR_IO_PENDING is never exposed and the _send_ov assignment window is negligible.
1 parent 8a0fa08 commit ca69664

1 file changed

Lines changed: 20 additions & 0 deletions

File tree

crates/vm/src/stdlib/_winapi.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,26 @@ mod _winapi {
12511251

12521252
err
12531253
};
1254+
1255+
// Without GIL, the Python-level PipeConnection._send_bytes has a
1256+
// race on _send_ov when the caller (SimpleQueue) skips locking on
1257+
// Windows. Wait for completion here so the caller never sees
1258+
// ERROR_IO_PENDING and never blocks in WaitForMultipleObjects,
1259+
// keeping the _send_ov window negligibly small.
1260+
if err == ERROR_IO_PENDING {
1261+
let event = ov.inner.lock().overlapped.hEvent;
1262+
vm.allow_threads(|| unsafe {
1263+
windows_sys::Win32::System::Threading::WaitForSingleObject(
1264+
event,
1265+
windows_sys::Win32::System::Threading::INFINITE,
1266+
);
1267+
});
1268+
let result = vm
1269+
.ctx
1270+
.new_tuple(vec![ov.into_pyobject(vm), vm.ctx.new_int(0u32).into()]);
1271+
return Ok(result.into());
1272+
}
1273+
12541274
let result = vm
12551275
.ctx
12561276
.new_tuple(vec![ov.into_pyobject(vm), vm.ctx.new_int(err).into()]);

0 commit comments

Comments
 (0)