Skip to content

FileIO.readinto() breaks the contract on io.RawIOBase.read() #118276

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
OlekTk opened this issue Apr 25, 2024 · 2 comments
Open

FileIO.readinto() breaks the contract on io.RawIOBase.read() #118276

OlekTk opened this issue Apr 25, 2024 · 2 comments
Labels
type-bug An unexpected behavior, bug, or error

Comments

@OlekTk
Copy link

OlekTk commented Apr 25, 2024

Bug report

Bug description:

The documentation of class io.RawIOBase claims that the 'read' method, when called with a specified transfer size, will perform only one system call ("Otherwise, only one system call is ever made."). However, in these circumstances, it relies on the 'readinto' implementation of a particular RawIOBase subclass. In the case of FileIO the 'readinto' method internally calls '_Py_read' (from fileutils.c) which contains a while loop around the 'read' system call, repeating it if it is interrupted by a signal and the current thread cannot handle the interrupt.

This looping behavior is surely convenient for the user, but it is also troubling in some corner cases. I work with a Linux device driver having a blocking 'read' method, which can only be interrupted by a signal. There are several data streams to capture, so I delegate them to different threads. When I have to interrupt the read (e.g. the machine readout trigger has not arrived) I send the signal to those threads (signal.pthread_kill). I see the driver intercepting it and aborting the transfer, then immediately the '_Py_read' repeats the system call starting another read and, in turn, causing my 'read' call never to return.

CPython versions tested on:

3.10

Operating systems tested on:

Linux

@OlekTk OlekTk added the type-bug An unexpected behavior, bug, or error label Apr 25, 2024
@Ryan-Carrier
Copy link

I am working on this issue.

@cmaloney
Copy link
Contributor

The retry loop was added for PEP-475 in Python 3.5. The docs should be updated to match the current behavior, I have been working on that in the implementation comments, will work on the more general I/O docs shortly. In particular, read() without a size will read until a zero-length return from the read underlying system call. The code comments in https://github.com/python/cpython/pull/129012/files are up to date for main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

3 participants