]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Move IOLoop subclasses to their own modules under platform.
authorBen Darnell <ben@bendarnell.com>
Sat, 6 Oct 2012 19:52:34 +0000 (12:52 -0700)
committerBen Darnell <ben@bendarnell.com>
Sun, 7 Oct 2012 04:11:54 +0000 (21:11 -0700)
maint/vm/ubuntu12.04/tox.ini
tornado/ioloop.py
tornado/platform/epoll.py [new file with mode: 0644]
tornado/platform/kqueue.py [new file with mode: 0644]
tornado/platform/select.py [new file with mode: 0644]
tox.ini

index 4098f883faf0eb7788e90d0ff56e239ed731f26a..fdf6f1f931761ab47fddcdffb30201ca0c294964 100644 (file)
@@ -1,5 +1,5 @@
 [tox]
-envlist = py27-full, py25-full, py32, py25, py27
+envlist = py27-full, py25-full, py32, py25, py27, py27-select
 setupdir=/tornado
 toxworkdir=/home/vagrant/tox-tornado
 
@@ -27,4 +27,12 @@ basepython = python2.7
 deps =
      futures
      pycurl
-     twisted==12.2.0
\ No newline at end of file
+     twisted==12.2.0
+
+[testenv:py27-select]
+basepython = python2.7
+deps =
+     futures
+     pycurl
+     twisted==12.2.0
+commands = python -m tornado.test.runtests --ioloop=tornado.platform.select.SelectIOLoop {posargs:}
index 1c7cddee7515ff58d56f911ca14a54f9cd72c868..2e1c65e84d0fb1197c9386b50cfe6ce9b468f8b6 100644 (file)
@@ -35,6 +35,7 @@ import heapq
 import logging
 import os
 import select
+import sys
 import thread
 import threading
 import time
@@ -103,20 +104,19 @@ class IOLoop(Configurable):
 
     @classmethod
     def configurable_default(cls):
-        if hasattr(select, "epoll"):
-            # Python 2.6+ on Linux
-            return EPollIOLoop
-        elif hasattr(select, "kqueue"):
+        if hasattr(select, "epoll") or sys.platform.startswith('linux'):
+            try:
+                from tornado.platform.epoll import EPollIOLoop
+                return EPollIOLoop
+            except ImportError:
+                gen_log.warning("unable to import EPollIOLoop, falling back to SelectIOLoop")
+                pass
+        if hasattr(select, "kqueue"):
             # Python 2.6+ on BSD or Mac
+            from tornado.platform.kqueue import KQueueIOLoop
             return KQueueIOLoop
-        else:
-            try:
-                # Python 2.5 on Linux with our C module installed
-                from tornado import epoll
-                return EPoll25IOLoop
-            except Exception:
-                # Everything else
-                return SelectIOLoop
+        from tornado.platform.select import SelectIOLoop
+        return SelectIOLoop
 
     # Constants from the epoll module
     _EPOLLIN = 0x001
@@ -663,163 +663,3 @@ class PeriodicCallback(object):
             while self._next_timeout <= current_time:
                 self._next_timeout += self.callback_time / 1000.0
             self._timeout = self.io_loop.add_timeout(self._next_timeout, self._run)
-
-
-class _EPoll(object):
-    """An epoll-based event loop using our C module for Python 2.5 systems"""
-    _EPOLL_CTL_ADD = 1
-    _EPOLL_CTL_DEL = 2
-    _EPOLL_CTL_MOD = 3
-
-    def __init__(self):
-        from tornado import epoll
-        self.epoll = epoll
-        self._epoll_fd = epoll.epoll_create()
-
-    def fileno(self):
-        return self._epoll_fd
-
-    def close(self):
-        os.close(self._epoll_fd)
-
-    def register(self, fd, events):
-        self.epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_ADD, fd, events)
-
-    def modify(self, fd, events):
-        self.epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_MOD, fd, events)
-
-    def unregister(self, fd):
-        self.epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_DEL, fd, 0)
-
-    def poll(self, timeout):
-        return self.epoll.epoll_wait(self._epoll_fd, int(timeout * 1000))
-
-
-class EPoll25IOLoop(IOLoop):
-    def initialize(self, **kwargs):
-        super(EPoll25IOLoop, self).initialize(impl=_EPoll(), **kwargs)
-
-
-class _KQueue(object):
-    """A kqueue-based event loop for BSD/Mac systems."""
-    def __init__(self):
-        self._kqueue = select.kqueue()
-        self._active = {}
-
-    def fileno(self):
-        return self._kqueue.fileno()
-
-    def close(self):
-        self._kqueue.close()
-
-    def register(self, fd, events):
-        if fd in self._active:
-            raise IOError("fd %d already registered" % fd)
-        self._control(fd, events, select.KQ_EV_ADD)
-        self._active[fd] = events
-
-    def modify(self, fd, events):
-        self.unregister(fd)
-        self.register(fd, events)
-
-    def unregister(self, fd):
-        events = self._active.pop(fd)
-        self._control(fd, events, select.KQ_EV_DELETE)
-
-    def _control(self, fd, events, flags):
-        kevents = []
-        if events & IOLoop.WRITE:
-            kevents.append(select.kevent(
-                    fd, filter=select.KQ_FILTER_WRITE, flags=flags))
-        if events & IOLoop.READ or not kevents:
-            # Always read when there is not a write
-            kevents.append(select.kevent(
-                    fd, filter=select.KQ_FILTER_READ, flags=flags))
-        # Even though control() takes a list, it seems to return EINVAL
-        # on Mac OS X (10.6) when there is more than one event in the list.
-        for kevent in kevents:
-            self._kqueue.control([kevent], 0)
-
-    def poll(self, timeout):
-        kevents = self._kqueue.control(None, 1000, timeout)
-        events = {}
-        for kevent in kevents:
-            fd = kevent.ident
-            if kevent.filter == select.KQ_FILTER_READ:
-                events[fd] = events.get(fd, 0) | IOLoop.READ
-            if kevent.filter == select.KQ_FILTER_WRITE:
-                if kevent.flags & select.KQ_EV_EOF:
-                    # If an asynchronous connection is refused, kqueue
-                    # returns a write event with the EOF flag set.
-                    # Turn this into an error for consistency with the
-                    # other IOLoop implementations.
-                    # Note that for read events, EOF may be returned before
-                    # all data has been consumed from the socket buffer,
-                    # so we only check for EOF on write events.
-                    events[fd] = IOLoop.ERROR
-                else:
-                    events[fd] = events.get(fd, 0) | IOLoop.WRITE
-            if kevent.flags & select.KQ_EV_ERROR:
-                events[fd] = events.get(fd, 0) | IOLoop.ERROR
-        return events.items()
-
-
-class KQueueIOLoop(IOLoop):
-    def initialize(self, **kwargs):
-        super(KQueueIOLoop, self).initialize(impl=_KQueue(), **kwargs)
-
-
-class _Select(object):
-    """A simple, select()-based IOLoop implementation for non-Linux systems"""
-    def __init__(self):
-        self.read_fds = set()
-        self.write_fds = set()
-        self.error_fds = set()
-        self.fd_sets = (self.read_fds, self.write_fds, self.error_fds)
-
-    def close(self):
-        pass
-
-    def register(self, fd, events):
-        if fd in self.read_fds or fd in self.write_fds or fd in self.error_fds:
-            raise IOError("fd %d already registered" % fd)
-        if events & IOLoop.READ:
-            self.read_fds.add(fd)
-        if events & IOLoop.WRITE:
-            self.write_fds.add(fd)
-        if events & IOLoop.ERROR:
-            self.error_fds.add(fd)
-            # Closed connections are reported as errors by epoll and kqueue,
-            # but as zero-byte reads by select, so when errors are requested
-            # we need to listen for both read and error.
-            self.read_fds.add(fd)
-
-    def modify(self, fd, events):
-        self.unregister(fd)
-        self.register(fd, events)
-
-    def unregister(self, fd):
-        self.read_fds.discard(fd)
-        self.write_fds.discard(fd)
-        self.error_fds.discard(fd)
-
-    def poll(self, timeout):
-        readable, writeable, errors = select.select(
-            self.read_fds, self.write_fds, self.error_fds, timeout)
-        events = {}
-        for fd in readable:
-            events[fd] = events.get(fd, 0) | IOLoop.READ
-        for fd in writeable:
-            events[fd] = events.get(fd, 0) | IOLoop.WRITE
-        for fd in errors:
-            events[fd] = events.get(fd, 0) | IOLoop.ERROR
-        return events.items()
-
-class SelectIOLoop(IOLoop):
-    def initialize(self, **kwargs):
-        super(SelectIOLoop, self).initialize(impl=_Select(), **kwargs)
-
-
-class EPollIOLoop(IOLoop):
-    def initialize(self, **kwargs):
-        super(EPollIOLoop, self).initialize(impl=select.epoll(), **kwargs)
diff --git a/tornado/platform/epoll.py b/tornado/platform/epoll.py
new file mode 100644 (file)
index 0000000..5a6af22
--- /dev/null
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 Facebook
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+"""EPoll-based IOLoop implementation for Linux systems.
+
+Supports the standard library's `select.epoll` function for Python 2.6+,
+and our own C module for Python 2.5.
+"""
+from __future__ import absolute_import, division, with_statement
+
+import os
+import select
+
+from tornado.ioloop import IOLoop
+
+if hasattr(select, 'epoll'):
+    # Python 2.6+
+    class EPollIOLoop(IOLoop):
+        def initialize(self, **kwargs):
+            super(EPollIOLoop, self).initialize(impl=select.epoll(), **kwargs)
+else:
+    # Python 2.5
+    from tornado import epoll
+    
+    class _EPoll(object):
+        """An epoll-based event loop using our C module for Python 2.5 systems"""
+        _EPOLL_CTL_ADD = 1
+        _EPOLL_CTL_DEL = 2
+        _EPOLL_CTL_MOD = 3
+
+        def __init__(self):
+            self._epoll_fd = epoll.epoll_create()
+
+        def fileno(self):
+            return self._epoll_fd
+
+        def close(self):
+            os.close(self._epoll_fd)
+
+        def register(self, fd, events):
+            epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_ADD, fd, events)
+
+        def modify(self, fd, events):
+            epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_MOD, fd, events)
+
+        def unregister(self, fd):
+            epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_DEL, fd, 0)
+
+        def poll(self, timeout):
+            return epoll.epoll_wait(self._epoll_fd, int(timeout * 1000))
+
+
+    class EPollIOLoop(IOLoop):
+        def initialize(self, **kwargs):
+            super(EPollIOLoop, self).initialize(impl=_EPoll(), **kwargs)
+
diff --git a/tornado/platform/kqueue.py b/tornado/platform/kqueue.py
new file mode 100644 (file)
index 0000000..45f4cc9
--- /dev/null
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 Facebook
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+"""KQueue-based IOLoop implementation for BSD/Mac systems."""
+from __future__ import absolute_import, division, with_statement
+
+import select
+
+from tornado.ioloop import IOLoop
+
+assert hasattr(select, 'kqueue'), 'kqueue not supported'
+
+class _KQueue(object):
+    """A kqueue-based event loop for BSD/Mac systems."""
+    def __init__(self):
+        self._kqueue = select.kqueue()
+        self._active = {}
+
+    def fileno(self):
+        return self._kqueue.fileno()
+
+    def close(self):
+        self._kqueue.close()
+
+    def register(self, fd, events):
+        if fd in self._active:
+            raise IOError("fd %d already registered" % fd)
+        self._control(fd, events, select.KQ_EV_ADD)
+        self._active[fd] = events
+
+    def modify(self, fd, events):
+        self.unregister(fd)
+        self.register(fd, events)
+
+    def unregister(self, fd):
+        events = self._active.pop(fd)
+        self._control(fd, events, select.KQ_EV_DELETE)
+
+    def _control(self, fd, events, flags):
+        kevents = []
+        if events & IOLoop.WRITE:
+            kevents.append(select.kevent(
+                    fd, filter=select.KQ_FILTER_WRITE, flags=flags))
+        if events & IOLoop.READ or not kevents:
+            # Always read when there is not a write
+            kevents.append(select.kevent(
+                    fd, filter=select.KQ_FILTER_READ, flags=flags))
+        # Even though control() takes a list, it seems to return EINVAL
+        # on Mac OS X (10.6) when there is more than one event in the list.
+        for kevent in kevents:
+            self._kqueue.control([kevent], 0)
+
+    def poll(self, timeout):
+        kevents = self._kqueue.control(None, 1000, timeout)
+        events = {}
+        for kevent in kevents:
+            fd = kevent.ident
+            if kevent.filter == select.KQ_FILTER_READ:
+                events[fd] = events.get(fd, 0) | IOLoop.READ
+            if kevent.filter == select.KQ_FILTER_WRITE:
+                if kevent.flags & select.KQ_EV_EOF:
+                    # If an asynchronous connection is refused, kqueue
+                    # returns a write event with the EOF flag set.
+                    # Turn this into an error for consistency with the
+                    # other IOLoop implementations.
+                    # Note that for read events, EOF may be returned before
+                    # all data has been consumed from the socket buffer,
+                    # so we only check for EOF on write events.
+                    events[fd] = IOLoop.ERROR
+                else:
+                    events[fd] = events.get(fd, 0) | IOLoop.WRITE
+            if kevent.flags & select.KQ_EV_ERROR:
+                events[fd] = events.get(fd, 0) | IOLoop.ERROR
+        return events.items()
+
+
+class KQueueIOLoop(IOLoop):
+    def initialize(self, **kwargs):
+        super(KQueueIOLoop, self).initialize(impl=_KQueue(), **kwargs)
diff --git a/tornado/platform/select.py b/tornado/platform/select.py
new file mode 100644 (file)
index 0000000..a8788ac
--- /dev/null
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 Facebook
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+"""Select-based IOLoop implementation.
+
+Used as a fallback for systems that don't support epoll or kqueue.
+"""
+from __future__ import absolute_import, division, with_statement
+
+import select
+
+from tornado.ioloop import IOLoop
+
+class _Select(object):
+    """A simple, select()-based IOLoop implementation for non-Linux systems"""
+    def __init__(self):
+        self.read_fds = set()
+        self.write_fds = set()
+        self.error_fds = set()
+        self.fd_sets = (self.read_fds, self.write_fds, self.error_fds)
+
+    def close(self):
+        pass
+
+    def register(self, fd, events):
+        if fd in self.read_fds or fd in self.write_fds or fd in self.error_fds:
+            raise IOError("fd %d already registered" % fd)
+        if events & IOLoop.READ:
+            self.read_fds.add(fd)
+        if events & IOLoop.WRITE:
+            self.write_fds.add(fd)
+        if events & IOLoop.ERROR:
+            self.error_fds.add(fd)
+            # Closed connections are reported as errors by epoll and kqueue,
+            # but as zero-byte reads by select, so when errors are requested
+            # we need to listen for both read and error.
+            self.read_fds.add(fd)
+
+    def modify(self, fd, events):
+        self.unregister(fd)
+        self.register(fd, events)
+
+    def unregister(self, fd):
+        self.read_fds.discard(fd)
+        self.write_fds.discard(fd)
+        self.error_fds.discard(fd)
+
+    def poll(self, timeout):
+        readable, writeable, errors = select.select(
+            self.read_fds, self.write_fds, self.error_fds, timeout)
+        events = {}
+        for fd in readable:
+            events[fd] = events.get(fd, 0) | IOLoop.READ
+        for fd in writeable:
+            events[fd] = events.get(fd, 0) | IOLoop.WRITE
+        for fd in errors:
+            events[fd] = events.get(fd, 0) | IOLoop.ERROR
+        return events.items()
+
+class SelectIOLoop(IOLoop):
+    def initialize(self, **kwargs):
+        super(SelectIOLoop, self).initialize(impl=_Select(), **kwargs)
+
diff --git a/tox.ini b/tox.ini
index 9525e795985d6f19eb081e30d05fe411eee35646..9adf8b5346fad7aa3664bedba91fcd6037cd907e 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -83,7 +83,7 @@ deps =
      futures
      pycurl
      twisted>=12.0.0
-commands = python -m tornado.test.runtests --ioloop=tornado.ioloop.SelectIOLoop {posargs:}
+commands = python -m tornado.test.runtests --ioloop=tornado.platform.select.SelectIOLoop {posargs:}
 
 [testenv:py27-monotonic]
 basepython = python2.7