From: Ben Darnell Date: Sat, 18 Jan 2014 21:42:06 +0000 (-0500) Subject: Make tornado.netutil.add_accept_handler pass a fileobj to the IOLoop. X-Git-Tag: v4.0.0b1~144 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=35ae2c5335b399d9ddb96036ec0a60728e0275d1;p=thirdparty%2Ftornado.git Make tornado.netutil.add_accept_handler pass a fileobj to the IOLoop. Officially allow mixing of fds and file objects so that callers of add_accept_handler don't need to know about this change. As a side effect, fixes a problem with autoreload on windows. Closes #737. --- diff --git a/tornado/netutil.py b/tornado/netutil.py index 8ebe604d2..7c89dc511 100644 --- a/tornado/netutil.py +++ b/tornado/netutil.py @@ -165,7 +165,7 @@ def add_accept_handler(sock, callback, io_loop=None): continue raise callback(connection, address) - io_loop.add_handler(sock.fileno(), accept_handler, IOLoop.READ) + io_loop.add_handler(sock, accept_handler, IOLoop.READ) def is_valid_ip(ip): diff --git a/tornado/platform/asyncio.py b/tornado/platform/asyncio.py index b6755e483..9b70cd4fb 100644 --- a/tornado/platform/asyncio.py +++ b/tornado/platform/asyncio.py @@ -24,7 +24,7 @@ class BaseAsyncIOLoop(IOLoop): self.asyncio_loop = asyncio_loop self.close_loop = close_loop self.asyncio_loop.call_soon(self.make_current) - # Maps fd to handler function (as in IOLoop.add_handler) + # Maps fd to (fileobj, handler function) pair (as in IOLoop.add_handler) self.handlers = {} # Set of fds listening for reads/writes self.readers = set() @@ -34,16 +34,18 @@ class BaseAsyncIOLoop(IOLoop): def close(self, all_fds=False): self.closing = True for fd in list(self.handlers): + fileobj, handler_func = self.handlers[fd] self.remove_handler(fd) if all_fds: - self.close_fd(fd) + self.close_fd(fileobj) if self.close_loop: self.asyncio_loop.close() def add_handler(self, fd, handler, events): + fd, fileobj = self.split_fd(fd) if fd in self.handlers: raise ValueError("fd %s added twice" % fd) - self.handlers[fd] = stack_context.wrap(handler) + self.handlers[fd] = (fileobj, stack_context.wrap(handler)) if events & IOLoop.READ: self.asyncio_loop.add_reader( fd, self._handle_events, fd, IOLoop.READ) @@ -54,6 +56,7 @@ class BaseAsyncIOLoop(IOLoop): self.writers.add(fd) def update_handler(self, fd, events): + fd, fileobj = self.split_fd(fd) if events & IOLoop.READ: if fd not in self.readers: self.asyncio_loop.add_reader( @@ -74,6 +77,7 @@ class BaseAsyncIOLoop(IOLoop): self.writers.remove(fd) def remove_handler(self, fd): + fd, fileobj = self.split_fd(fd) if fd not in self.handlers: return if fd in self.readers: @@ -85,7 +89,8 @@ class BaseAsyncIOLoop(IOLoop): del self.handlers[fd] def _handle_events(self, fd, events): - self.handlers[fd](fd, events) + fileobj, handler_func = self.handlers[fd] + handler_func(fileobj, events) def start(self): self._setup_logging() diff --git a/tornado/test/ioloop_test.py b/tornado/test/ioloop_test.py index 3e888d3dd..460dc50f7 100644 --- a/tornado/test/ioloop_test.py +++ b/tornado/test/ioloop_test.py @@ -223,6 +223,18 @@ class TestIOLoop(AsyncTestCase): self.io_loop.remove_handler(server_sock.fileno()) server_sock.close() + def test_mixed_fd_fileobj(self): + server_sock, port = bind_unused_port() + def f(fd, events): + pass + self.io_loop.add_handler(server_sock, f, IOLoop.READ) + with self.assertRaises(Exception): + # The exact error is unspecified - some implementations use + # IOError, others use ValueError. + self.io_loop.add_handler(server_sock.fileno(), f, IOLoop.READ) + self.io_loop.remove_handler(server_sock.fileno()) + server_sock.close() + # Deliberately not a subclass of AsyncTestCase so the IOLoop isn't