diff --git a/Lib/test/_test_eintr.py b/Lib/test/_test_eintr.py index a826d31bcd..095ccd032b 100644 --- a/Lib/test/_test_eintr.py +++ b/Lib/test/_test_eintr.py @@ -392,7 +392,6 @@ def test_os_open(self): 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) diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 5a3f0744ad..7420f289b1 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -614,7 +614,6 @@ def assertNotOrderable(self, a, b): with self.assertRaises(TypeError): a >= b - @unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; AssertionError: 1543448294720 != 1543448295392") def testHashComparisonOfMethods(self): # Test comparison and hash of methods class A: diff --git a/crates/stdlib/src/multiprocessing.rs b/crates/stdlib/src/multiprocessing.rs index 26d1bea885..fe30abfdcb 100644 --- a/crates/stdlib/src/multiprocessing.rs +++ b/crates/stdlib/src/multiprocessing.rs @@ -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 => { diff --git a/crates/vm/src/stdlib/time.rs b/crates/vm/src/stdlib/time.rs index d38152db84..9235d8c89b 100644 --- a/crates/vm/src/stdlib/time.rs +++ b/crates/vm/src/stdlib/time.rs @@ -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()?; } }