Skip to content

Commit bca89e6

Browse files
committed
Match Windows select capacity to Python 3.14
Use a 512-entry WinSock fd_set with checked C layout and scan its returned socket array. Keep the SDK default-size declaration at the FFI boundary only. The preceding regression-only commit passed CPython 3.14.7 on hosted Windows and failed RustPython at the first 65-socket selection. Windows-GNU host_env cargo check and Clippy with warnings denied pass. The fixed native Windows runtime result remains pending CI. AI assistance covered source comparison, implementation, regression design, and automated verification. No manual validation is claimed. Assisted-by: Codex:model-version-unavailable
1 parent 4de6987 commit bca89e6

1 file changed

Lines changed: 55 additions & 3 deletions

File tree

‎crates/host_env/src/select.rs‎

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,62 @@ pub mod platform {
3636
#[allow(non_snake_case)]
3737
#[cfg(windows)]
3838
pub mod platform {
39-
pub use WinSock::{FD_SET as fd_set, FD_SETSIZE, SOCKET as RawFd, TIMEVAL as timeval, select};
39+
pub use WinSock::{SOCKET as RawFd, TIMEVAL as timeval};
4040
use std::io;
4141
use windows_sys::Win32::Networking::WinSock;
4242

43+
// Match CPython's Windows capacity. WinSock uses fd_count to determine
44+
// the array length; the windows-sys declaration has the SDK default of 64.
45+
pub const FD_SETSIZE: u32 = 512;
46+
47+
#[allow(non_camel_case_types)]
48+
#[repr(C)]
49+
pub struct fd_set {
50+
fd_count: u32,
51+
fd_array: [RawFd; FD_SETSIZE as usize],
52+
}
53+
54+
const _: () = {
55+
assert!(core::mem::align_of::<fd_set>() == core::mem::align_of::<WinSock::FD_SET>());
56+
assert!(
57+
core::mem::offset_of!(fd_set, fd_count)
58+
== core::mem::offset_of!(WinSock::FD_SET, fd_count)
59+
);
60+
assert!(
61+
core::mem::offset_of!(fd_set, fd_array)
62+
== core::mem::offset_of!(WinSock::FD_SET, fd_array)
63+
);
64+
assert!(
65+
core::mem::size_of::<fd_set>()
66+
== core::mem::offset_of!(fd_set, fd_array)
67+
+ FD_SETSIZE as usize * core::mem::size_of::<RawFd>()
68+
);
69+
};
70+
71+
/// # Safety
72+
///
73+
/// Every non-null set must point to an initialized fd_set, and timeout
74+
/// must be null or point to an initialized timeval.
75+
pub unsafe fn select(
76+
nfds: i32,
77+
readfds: *mut fd_set,
78+
writefds: *mut fd_set,
79+
errorfds: *mut fd_set,
80+
timeout: *const timeval,
81+
) -> i32 {
82+
// fd_set is a count followed by a caller-sized SOCKET array. Both
83+
// layouts have the same alignment and offset of the array.
84+
unsafe {
85+
WinSock::select(
86+
nfds,
87+
readfds.cast(),
88+
writefds.cast(),
89+
errorfds.cast(),
90+
timeout,
91+
)
92+
}
93+
}
94+
4395
/// # Safety
4496
///
4597
/// `set` must be a valid mutable pointer to an initialized WinSock fd_set.
@@ -71,8 +123,8 @@ pub mod platform {
71123
///
72124
/// `set` must be a valid mutable pointer to an initialized WinSock fd_set.
73125
pub unsafe fn FD_ISSET(fd: RawFd, set: *mut fd_set) -> bool {
74-
use WinSock::__WSAFDIsSet;
75-
unsafe { __WSAFDIsSet(fd as _, set) != 0 }
126+
let set = unsafe { &*set };
127+
set.fd_array[..set.fd_count as usize].contains(&fd)
76128
}
77129

78130
#[must_use]

0 commit comments

Comments
 (0)