Skip to content

Commit 53162f8

Browse files
youknowoneCopilot
authored andcommitted
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
1 parent 49fccd6 commit 53162f8

File tree

4 files changed

+26
-14
lines changed

4 files changed

+26
-14
lines changed

Lib/test/_test_eintr.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,6 @@ def test_os_open(self):
392392
class TimeEINTRTest(EINTRBaseTest):
393393
""" EINTR tests for the time module. """
394394

395-
@unittest.expectedFailure # TODO: RUSTPYTHON
396395
def test_sleep(self):
397396
t0 = time.monotonic()
398397
time.sleep(self.sleep_time)

Lib/test/test_class.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,6 @@ def assertNotOrderable(self, a, b):
614614
with self.assertRaises(TypeError):
615615
a >= b
616616

617-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; AssertionError: 1543448294720 != 1543448295392")
618617
def testHashComparisonOfMethods(self):
619618
# Test comparison and hash of methods
620619
class A:

crates/stdlib/src/multiprocessing.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ mod _multiprocessing {
193193
remaining.min(poll_ms)
194194
};
195195

196-
let res = unsafe { WaitForSingleObjectEx(self.handle.as_raw(), wait_ms, 0) };
196+
let handle = self.handle.as_raw();
197+
let res = vm.allow_threads(|| unsafe { WaitForSingleObjectEx(handle, wait_ms, 0) });
197198

198199
match res {
199200
WAIT_OBJECT_0 => {

crates/vm/src/stdlib/time.rs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,30 @@ mod decl {
115115

116116
#[cfg(unix)]
117117
{
118-
// this is basically std::thread::sleep, but that catches interrupts and we don't want to;
119-
let ts = nix::sys::time::TimeSpec::from(dur);
120-
// Capture errno inside the closure: attach_thread (called by
121-
// allow_threads on return) can clobber errno via syscalls.
122-
let (res, err) = vm.allow_threads(|| {
123-
let r = unsafe { libc::nanosleep(ts.as_ref(), core::ptr::null_mut()) };
124-
(r, nix::Error::last_raw())
125-
});
126-
let interrupted = res == -1 && err == libc::EINTR;
127-
128-
if interrupted {
118+
// Loop on nanosleep, recomputing the
119+
// remaining timeout after each EINTR so that signals don't
120+
// shorten the requested sleep duration.
121+
use std::time::Instant;
122+
let deadline = Instant::now() + dur;
123+
loop {
124+
let remaining = deadline.saturating_duration_since(Instant::now());
125+
if remaining.is_zero() {
126+
break;
127+
}
128+
let ts = nix::sys::time::TimeSpec::from(remaining);
129+
let (res, err) = vm.allow_threads(|| {
130+
let r = unsafe { libc::nanosleep(ts.as_ref(), core::ptr::null_mut()) };
131+
(r, nix::Error::last_raw())
132+
});
133+
if res == 0 {
134+
break;
135+
}
136+
if err != libc::EINTR {
137+
return Err(
138+
vm.new_os_error(format!("nanosleep: {}", nix::Error::from_raw(err)))
139+
);
140+
}
141+
// EINTR: run signal handlers, then retry with remaining time
129142
vm.check_signals()?;
130143
}
131144
}

0 commit comments

Comments
 (0)