Skip to content

Commit a670799

Browse files
authored
Fix EINTR handling (RustPython#7204)
1 parent ccfa938 commit a670799

File tree

1 file changed

+37
-20
lines changed
  • crates/vm/src/stdlib

1 file changed

+37
-20
lines changed

crates/vm/src/stdlib/io.rs

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,29 +1000,39 @@ mod _io {
10001000
vm: &VirtualMachine,
10011001
) -> PyResult<Option<usize>> {
10021002
let len = buf_range.len();
1003-
let res = if let Some(buf) = buf {
1004-
let mem_obj = PyMemoryView::from_buffer_range(buf, buf_range, vm)?.to_pyobject(vm);
10051003

1006-
// TODO: loop if write() raises an interrupt
1007-
vm.call_method(self.raw.as_ref().unwrap(), "write", (mem_obj,))?
1004+
// Prepare the memoryview; if using the internal buffer, stash it
1005+
// in write_buf so we can restore it after the write.
1006+
let (mem_obj, write_buf) = if let Some(buf) = buf {
1007+
let mem_obj =
1008+
PyMemoryView::from_buffer_range(buf, buf_range, vm)?.into_ref(&vm.ctx);
1009+
(mem_obj, None)
10081010
} else {
10091011
let v = core::mem::take(&mut self.buffer);
1010-
let write_buf = VecBuffer::from(v).into_ref(&vm.ctx);
1011-
let mem_obj = PyMemoryView::from_buffer_range(
1012-
write_buf.clone().into_pybuffer(true),
1013-
buf_range,
1014-
vm,
1015-
)?
1016-
.into_ref(&vm.ctx);
1012+
let wb = VecBuffer::from(v).into_ref(&vm.ctx);
1013+
let mem_obj =
1014+
PyMemoryView::from_buffer_range(wb.clone().into_pybuffer(true), buf_range, vm)?
1015+
.into_ref(&vm.ctx);
1016+
(mem_obj, Some(wb))
1017+
};
10171018

1018-
// TODO: loop if write() raises an interrupt
1019+
// Loop if write() raises EINTR (PEP 475)
1020+
let res = loop {
10191021
let res = vm.call_method(self.raw.as_ref().unwrap(), "write", (mem_obj.clone(),));
1022+
match trap_eintr(res, vm) {
1023+
Ok(Some(val)) => break Ok(val),
1024+
Ok(None) => continue,
1025+
Err(e) => break Err(e),
1026+
}
1027+
};
10201028

1029+
// Restore internal buffer if we borrowed it
1030+
if let Some(wb) = write_buf {
10211031
mem_obj.release();
1022-
self.buffer = write_buf.take();
1032+
self.buffer = wb.take();
1033+
}
10231034

1024-
res?
1025-
};
1035+
let res = res?;
10261036

10271037
if vm.is_none(&res) {
10281038
return Ok(None);
@@ -5737,11 +5747,18 @@ mod fileio {
57375747

57385748
let mut handle = zelf.get_fd(vm)?;
57395749

5740-
let len = match obj.with_ref(|b| handle.write(b)) {
5741-
Ok(n) => n,
5742-
// Non-blocking mode: return None if EAGAIN
5743-
Err(e) if e.raw_os_error() == Some(libc::EAGAIN) => return Ok(None),
5744-
Err(e) => return Err(Self::io_error(zelf, e, vm)),
5750+
// Loop on EINTR (PEP 475)
5751+
let len = loop {
5752+
match obj.with_ref(|b| handle.write(b)) {
5753+
Ok(n) => break n,
5754+
Err(e) if e.raw_os_error() == Some(libc::EINTR) => {
5755+
vm.check_signals()?;
5756+
continue;
5757+
}
5758+
// Non-blocking mode: return None if EAGAIN
5759+
Err(e) if e.raw_os_error() == Some(libc::EAGAIN) => return Ok(None),
5760+
Err(e) => return Err(Self::io_error(zelf, e, vm)),
5761+
}
57455762
};
57465763

57475764
//return number of bytes written

0 commit comments

Comments
 (0)