pmonitor() fixes

pmonitor() is hard to get right, but this seems like
a reasonable improvement:

1. non-blocking I/O so we can drain buffer with impunity
2. drain buffer after poll
3. unregister fd on POLLHUP

Note we may have a unicode splitting problem since we're
decoding chunks of bytes, but that is a problem for another
day I think.
This commit is contained in:
Bob Lantz
2018-08-02 12:45:35 -07:00
parent 3bcecd8e08
commit 5100a38fcd
+12 -19
View File
@@ -416,34 +416,27 @@ def pmonitor(popens, timeoutms=500, readline=True,
for host, popen in popens.items(): for host, popen in popens.items():
fd = popen.stdout.fileno() fd = popen.stdout.fileno()
fdToHost[ fd ] = host fdToHost[ fd ] = host
poller.register( fd, POLLIN ) poller.register( fd, POLLIN | POLLHUP )
if not readline: flags = fcntl( fd, F_GETFL )
# Use non-blocking reads fcntl( fd, F_SETFL, flags | O_NONBLOCK )
flags = fcntl( fd, F_GETFL )
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
def readit( f ):
"Helper function - read line or data"
# Note this will block if readline is True
line = f.readline() if readline else f.read( readmax )
return decode( line )
while popens: while popens:
fds = poller.poll( timeoutms ) fds = poller.poll( timeoutms )
if fds: if fds:
for fd, event in fds: for fd, event in fds:
host = fdToHost[ fd ] host = fdToHost[ fd ]
popen = popens[ host ] popen = popens[ host ]
if event & POLLIN: if event & POLLIN or event & POLLHUP:
line = readit( popen.stdout )
yield host, line
if event & POLLHUP:
while True: while True:
# Drain buffer try:
line = readit( popen.stdout ) f = popen.stdout
yield host, line line = decode( f.readline() if readline
else f.read( readmax ) )
except IOError:
line = ''
if line == '': if line == '':
break break
yield host, line
if event & POLLHUP:
poller.unregister( fd ) poller.unregister( fd )
del popens[ host ] del popens[ host ]
else: else: