Commit 2d7fe7d0 authored by Jason Madden's avatar Jason Madden

The gevent.select.poll object must keep a tighter handle on the lifetime of io...

The gevent.select.poll object must keep a tighter handle on the lifetime of io watchers it spawns. Previously they were leaking if not unregistered, which some callers fail to do --- looking at you, dnspython.
parent e093d31d
...@@ -253,7 +253,9 @@ _is_ipv4_addr = _is_addr ...@@ -253,7 +253,9 @@ _is_ipv4_addr = _is_addr
def _is_ipv6_addr(host): def _is_ipv6_addr(host):
# Return True if host is a valid IPv6 address # Return True if host is a valid IPv6 address
host = host.split('%', 1)[0] if host else host if host:
s = '%' if isinstance(host, str) else b'%'
host = host.split(s, 1)[0]
return _is_addr(host, dns.ipv6.inet_aton) return _is_addr(host, dns.ipv6.inet_aton)
class HostsFile(object): class HostsFile(object):
......
...@@ -11,7 +11,6 @@ from gevent.hub import get_hub ...@@ -11,7 +11,6 @@ from gevent.hub import get_hub
from gevent.hub import sleep as _g_sleep from gevent.hub import sleep as _g_sleep
from gevent._compat import integer_types from gevent._compat import integer_types
from gevent._compat import iteritems from gevent._compat import iteritems
from gevent._compat import itervalues
from gevent._util import copy_globals from gevent._util import copy_globals
from gevent._util import _NONE from gevent._util import _NONE
...@@ -200,7 +199,11 @@ if original_poll is not None: ...@@ -200,7 +199,11 @@ if original_poll is not None:
.. versionadded:: 1.1b1 .. versionadded:: 1.1b1
""" """
def __init__(self): def __init__(self):
self.fds = {} # {int -> watcher} # {int -> flags}
# We can't keep watcher objects in here because people commonly
# just drop the poll object when they're done, without calling
# unregister(). dnspython does this.
self.fds = {}
self.loop = get_hub().loop self.loop = get_hub().loop
def register(self, fd, eventmask=_NONE): def register(self, fd, eventmask=_NONE):
...@@ -216,12 +219,7 @@ if original_poll is not None: ...@@ -216,12 +219,7 @@ if original_poll is not None:
# that. Should we raise an error? # that. Should we raise an error?
fileno = get_fileno(fd) fileno = get_fileno(fd)
if fileno in self.fds: self.fds[fileno] = flags
self.fds[fileno].close()
watcher = self.loop.io(fileno, flags)
watcher.priority = self.loop.MAXPRI
self.fds[fileno] = watcher
def modify(self, fd, eventmask): def modify(self, fd, eventmask):
self.register(fd, eventmask) self.register(fd, eventmask)
...@@ -234,16 +232,23 @@ if original_poll is not None: ...@@ -234,16 +232,23 @@ if original_poll is not None:
File descriptors that are closed are reported with POLLNVAL. File descriptors that are closed are reported with POLLNVAL.
""" """
result = PollResult() result = PollResult()
watchers = []
io = self.loop.io
MAXPRI = self.loop.MAXPRI
try: try:
for fd, watcher in iteritems(self.fds): for fd, flags in iteritems(self.fds):
watcher = io(fd, flags)
watchers.append(watcher)
watcher.priority = MAXPRI
watcher.start(result.add_event, fd, pass_events=True) watcher.start(result.add_event, fd, pass_events=True)
if timeout is not None and timeout > -1: if timeout is not None and timeout > -1:
timeout /= 1000.0 timeout /= 1000.0
result.event.wait(timeout=timeout) result.event.wait(timeout=timeout)
return list(result.events) return list(result.events)
finally: finally:
for awatcher in itervalues(self.fds): for awatcher in watchers:
awatcher.stop() awatcher.stop()
awatcher.close()
def unregister(self, fd): def unregister(self, fd):
""" """
...@@ -254,8 +259,6 @@ if original_poll is not None: ...@@ -254,8 +259,6 @@ if original_poll is not None:
library. Previously gevent did nothing. library. Previously gevent did nothing.
""" """
fileno = get_fileno(fd) fileno = get_fileno(fd)
io = self.fds[fileno]
io.close()
del self.fds[fileno] del self.fds[fileno]
del original_poll del original_poll
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment