Fix allow_threads and EINTR handling (#7457)

* Fix allow_threads and EINTR handling

- Wrap Windows SemLock acquire wait with allow_threads
- Retry nanosleep on EINTR with remaining time instead of
  returning early
- Remove expectedFailure for test_sleep in _test_eintr.py

* Remove expectedFailureIfWindows for testHashComparisonOfMethods
This commit is contained in:
Jeong, YunWon authored and GitHub committed 2026-03-20 19:59:13 +09:00
1 parent 247044a805
commit 8be5230a9b
4 files changed
+26 -14

No files matched your search

-1
View File
@@ -392,7 +392,6 @@ class SocketEINTRTest(EINTRBaseTest):
class TimeEINTRTest(EINTRBaseTest):
""" EINTR tests for the time module. """
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_sleep(self):
t0 = time.monotonic()
time.sleep(self.sleep_time)
-1
View File
@@ -614,7 +614,6 @@ class ClassTests(unittest.TestCase):
with self.assertRaises(TypeError):
a >= b
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; AssertionError: 1543448294720 != 1543448295392")
def testHashComparisonOfMethods(self):
# Test comparison and hash of methods
class A:
+2 -1
View File
@@ -193,7 +193,8 @@ mod _multiprocessing {
remaining.min(poll_ms)
};
let res = unsafe { WaitForSingleObjectEx(self.handle.as_raw(), wait_ms, 0) };
let handle = self.handle.as_raw();
let res = vm.allow_threads(|| unsafe { WaitForSingleObjectEx(handle, wait_ms, 0) });
match res {
WAIT_OBJECT_0 => {
+24 -11
View File
@@ -115,17 +115,30 @@ mod decl {
#[cfg(unix)]
{
// this is basically std::thread::sleep, but that catches interrupts and we don't want to;
let ts = nix::sys::time::TimeSpec::from(dur);
// Capture errno inside the closure: attach_thread (called by
// allow_threads on return) can clobber errno via syscalls.
let (res, err) = vm.allow_threads(|| {
let r = unsafe { libc::nanosleep(ts.as_ref(), core::ptr::null_mut()) };
(r, nix::Error::last_raw())
});
let interrupted = res == -1 && err == libc::EINTR;
if interrupted {
// Loop on nanosleep, recomputing the
// remaining timeout after each EINTR so that signals don't
// shorten the requested sleep duration.
use std::time::Instant;
let deadline = Instant::now() + dur;
loop {
let remaining = deadline.saturating_duration_since(Instant::now());
if remaining.is_zero() {
break;
}
let ts = nix::sys::time::TimeSpec::from(remaining);
let (res, err) = vm.allow_threads(|| {
let r = unsafe { libc::nanosleep(ts.as_ref(), core::ptr::null_mut()) };
(r, nix::Error::last_raw())
});
if res == 0 {
break;
}
if err != libc::EINTR {
return Err(
vm.new_os_error(format!("nanosleep: {}", nix::Error::from_raw(err)))
);
}
// EINTR: run signal handlers, then retry with remaining time
vm.check_signals()?;
}
}