python / cpython

The Python programming language
https://www.python.org
Other
62.31k stars 29.93k forks source link

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

Open OlekTk opened 4 months ago

OlekTk commented 4 months ago

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

RyanCarrierT commented 4 months ago

I am working on this issue.