mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
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:
1 parent
247044a805
commit
8be5230a9b
4 files changed
+26
-14
No files matched your search
Vendored
-1
@@ -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)
|
||||
|
||||
Vendored
-1
@@ -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:
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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()?;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user