Linux will fire poll() with simply the POLLHUP bit set even though it was not requested, resulting in an infinite loop.
This commit is contained in:
parent
07f1b9bdd0
commit
19b708e141
|
@ -1900,8 +1900,10 @@ class Poller(object):
|
|||
"""
|
||||
pass
|
||||
|
||||
_readmask = select.POLLIN | select.POLLHUP
|
||||
|
||||
def _update(self, fd):
|
||||
mask = (((fd in self._rfds) and select.POLLIN) |
|
||||
mask = (((fd in self._rfds) and self._readmask) |
|
||||
((fd in self._wfds) and select.POLLOUT))
|
||||
if mask:
|
||||
self._pollobj.register(fd, mask)
|
||||
|
@ -1951,8 +1953,8 @@ class Poller(object):
|
|||
|
||||
events, _ = io_op(self._pollobj.poll, timeout)
|
||||
for fd, event in events:
|
||||
if event & select.POLLIN:
|
||||
_vv and IOLOG.debug('%r: POLLIN for %r', self, fd)
|
||||
if event & self._readmask:
|
||||
_vv and IOLOG.debug('%r: POLLIN|POLLHUP for %r', self, fd)
|
||||
data, gen = self._rfds.get(fd, (None, None))
|
||||
if gen and gen < self._generation:
|
||||
yield data
|
||||
|
|
|
@ -13,6 +13,12 @@ import mitogen.parent
|
|||
|
||||
import testlib
|
||||
|
||||
try:
|
||||
next
|
||||
except NameError:
|
||||
# Python 2.4
|
||||
from mitogen.core import next
|
||||
|
||||
|
||||
class SockMixin(object):
|
||||
def tearDown(self):
|
||||
|
@ -345,6 +351,22 @@ class FileClosedMixin(PollerMixin, SockMixin):
|
|||
pass
|
||||
|
||||
|
||||
class TtyHangupMixin(PollerMixin):
|
||||
def test_tty_hangup_detected(self):
|
||||
# bug in initial select.poll() implementation failed to detect POLLHUP.
|
||||
master_fd, slave_fd = mitogen.parent.openpty()
|
||||
try:
|
||||
self.p.start_receive(master_fd)
|
||||
self.assertEquals([], list(self.p.poll(0)))
|
||||
os.close(slave_fd)
|
||||
slave_fd = None
|
||||
self.assertEquals([master_fd], list(self.p.poll(0)))
|
||||
finally:
|
||||
if slave_fd is not None:
|
||||
os.close(slave_fd)
|
||||
os.close(master_fd)
|
||||
|
||||
|
||||
class DistinctDataMixin(PollerMixin, SockMixin):
|
||||
# Verify different data is yielded for the same FD according to the event
|
||||
# being raised.
|
||||
|
@ -368,29 +390,39 @@ class AllMixin(ReceiveStateMixin,
|
|||
FileClosedMixin,
|
||||
DistinctDataMixin,
|
||||
PollMixin,
|
||||
TtyHangupMixin,
|
||||
CloseMixin):
|
||||
"""
|
||||
Helper to avoid cutpasting mixin names below.
|
||||
"""
|
||||
|
||||
|
||||
@unittest2.skipIf(condition=not hasattr(select, 'select'),
|
||||
reason='select.select() not supported')
|
||||
class SelectTest(AllMixin, testlib.TestCase):
|
||||
klass = mitogen.core.Poller
|
||||
|
||||
SelectTest = unittest2.skipIf(
|
||||
condition=not hasattr(select, 'select'),
|
||||
reason='select.select() not supported'
|
||||
)(SelectTest)
|
||||
|
||||
|
||||
@unittest2.skipIf(condition=not hasattr(select, 'kqueue'),
|
||||
reason='select.kqueue() not supported')
|
||||
class KqueueTest(AllMixin, testlib.TestCase):
|
||||
klass = mitogen.parent.KqueuePoller
|
||||
|
||||
KqueueTest = unittest2.skipIf(
|
||||
condition=not hasattr(select, 'kqueue'),
|
||||
reason='select.kqueue() not supported'
|
||||
)(KqueueTest)
|
||||
|
||||
|
||||
@unittest2.skipIf(condition=not hasattr(select, 'epoll'),
|
||||
reason='select.epoll() not supported')
|
||||
class EpollTest(AllMixin, testlib.TestCase):
|
||||
klass = mitogen.parent.EpollPoller
|
||||
|
||||
EpollTest = unittest2.skipIf(
|
||||
condition=not hasattr(select, 'epoll'),
|
||||
reason='select.epoll() not supported'
|
||||
)(EpollTest)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest2.main()
|
||||
|
|
Loading…
Reference in New Issue