issue #148: parent: prevent race in iter_read()

There is no guarantee on the ordering select() returns file descriptors.
So if, e.g. in the case of sudo_nonexistent.yml, sudo prints an error
to a single FD before exitting, there was previously no gurantee
iter_read() would read off the error before failing due to detecting
disconnect on any FD.

Now instead we keep reading while any non-disconnected FD exists.
pull/194/head
David Wilson 7 years ago
parent e43c6c531b
commit 46a311165e

@ -51,7 +51,7 @@ echo \
# Build the binaries. # Build the binaries.
make -C ${TRAVIS_BUILD_DIR}/tests/ansible make -C ${TRAVIS_BUILD_DIR}/tests/ansible
sudo apt install -y sshpass [ ! "$(type -p sshpass)" ] && sudo apt install -y sshpass
echo travis_fold:end:job_setup echo travis_fold:end:job_setup

@ -379,10 +379,11 @@ def write_all(fd, s, deadline=None):
def iter_read(fds, deadline=None): def iter_read(fds, deadline=None):
fds = list(fds)
bits = [] bits = []
timeout = None timeout = None
while True: while fds:
if deadline is not None: if deadline is not None:
timeout = max(0, deadline - time.time()) timeout = max(0, deadline - time.time())
if timeout == 0: if timeout == 0:
@ -394,15 +395,19 @@ def iter_read(fds, deadline=None):
for fd in rfds: for fd in rfds:
s, disconnected = mitogen.core.io_op(os.read, fd, 4096) s, disconnected = mitogen.core.io_op(os.read, fd, 4096)
IOLOG.debug('iter_read(%r) -> %r', fd, s)
if disconnected or not s: if disconnected or not s:
raise mitogen.core.StreamError( IOLOG.debug('iter_read(%r) -> disconnected', fd)
'EOF on stream; last 300 bytes received: %r' % fds.remove(fd)
(''.join(bits)[-300:],) else:
) IOLOG.debug('iter_read(%r) -> %r', fd, s)
bits.append(s)
bits.append(s) yield s
yield s
if not fds:
raise mitogen.core.StreamError(
'EOF on stream; last 300 bytes received: %r' %
(''.join(bits)[-300:],)
)
raise mitogen.core.TimeoutError('read timed out') raise mitogen.core.TimeoutError('read timed out')

Loading…
Cancel
Save