IOLoop poller implementations are now subclasses of IOLoop.
Update testing command-line flags to allow configuration of a non-default IOLoop.
This commit is contained in:
parent
91c5eb83f9
commit
469e227402
|
@ -103,7 +103,20 @@ class IOLoop(Configurable):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def configurable_default(cls):
|
def configurable_default(cls):
|
||||||
return IOLoop
|
if hasattr(select, "epoll"):
|
||||||
|
# Python 2.6+ on Linux
|
||||||
|
return EPollIOLoop
|
||||||
|
elif hasattr(select, "kqueue"):
|
||||||
|
# Python 2.6+ on BSD or Mac
|
||||||
|
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
|
||||||
|
|
||||||
# Constants from the epoll module
|
# Constants from the epoll module
|
||||||
_EPOLLIN = 0x001
|
_EPOLLIN = 0x001
|
||||||
|
@ -126,8 +139,8 @@ class IOLoop(Configurable):
|
||||||
|
|
||||||
_current = threading.local()
|
_current = threading.local()
|
||||||
|
|
||||||
def initialize(self, impl=None):
|
def initialize(self, impl):
|
||||||
self._impl = impl or _poll()
|
self._impl = impl
|
||||||
if hasattr(self._impl, 'fileno'):
|
if hasattr(self._impl, 'fileno'):
|
||||||
set_close_exec(self._impl.fileno())
|
set_close_exec(self._impl.fileno())
|
||||||
self._handlers = {}
|
self._handlers = {}
|
||||||
|
@ -643,6 +656,8 @@ class _EPoll(object):
|
||||||
_EPOLL_CTL_MOD = 3
|
_EPOLL_CTL_MOD = 3
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
from tornado import epoll
|
||||||
|
self.epoll = epoll
|
||||||
self._epoll_fd = epoll.epoll_create()
|
self._epoll_fd = epoll.epoll_create()
|
||||||
|
|
||||||
def fileno(self):
|
def fileno(self):
|
||||||
|
@ -652,16 +667,21 @@ class _EPoll(object):
|
||||||
os.close(self._epoll_fd)
|
os.close(self._epoll_fd)
|
||||||
|
|
||||||
def register(self, fd, events):
|
def register(self, fd, events):
|
||||||
epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_ADD, fd, events)
|
self.epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_ADD, fd, events)
|
||||||
|
|
||||||
def modify(self, fd, events):
|
def modify(self, fd, events):
|
||||||
epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_MOD, fd, events)
|
self.epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_MOD, fd, events)
|
||||||
|
|
||||||
def unregister(self, fd):
|
def unregister(self, fd):
|
||||||
epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_DEL, fd, 0)
|
self.epoll.epoll_ctl(self._epoll_fd, self._EPOLL_CTL_DEL, fd, 0)
|
||||||
|
|
||||||
def poll(self, timeout):
|
def poll(self, timeout):
|
||||||
return epoll.epoll_wait(self._epoll_fd, int(timeout * 1000))
|
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):
|
class _KQueue(object):
|
||||||
|
@ -728,6 +748,11 @@ class _KQueue(object):
|
||||||
return events.items()
|
return events.items()
|
||||||
|
|
||||||
|
|
||||||
|
class KQueueIOLoop(IOLoop):
|
||||||
|
def initialize(self, **kwargs):
|
||||||
|
super(KQueueIOLoop, self).initialize(impl=_KQueue(), **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class _Select(object):
|
class _Select(object):
|
||||||
"""A simple, select()-based IOLoop implementation for non-Linux systems"""
|
"""A simple, select()-based IOLoop implementation for non-Linux systems"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -774,23 +799,11 @@ class _Select(object):
|
||||||
events[fd] = events.get(fd, 0) | IOLoop.ERROR
|
events[fd] = events.get(fd, 0) | IOLoop.ERROR
|
||||||
return events.items()
|
return events.items()
|
||||||
|
|
||||||
|
class SelectIOLoop(IOLoop):
|
||||||
|
def initialize(self, **kwargs):
|
||||||
|
super(SelectIOLoop, self).initialize(impl=_Select(), **kwargs)
|
||||||
|
|
||||||
# Choose a poll implementation. Use epoll if it is available, fall back to
|
|
||||||
# select() for non-Linux platforms
|
class EPollIOLoop(IOLoop):
|
||||||
if hasattr(select, "epoll"):
|
def initialize(self, **kwargs):
|
||||||
# Python 2.6+ on Linux
|
super(EPollIOLoop, self).initialize(impl=select.epoll(), **kwargs)
|
||||||
_poll = select.epoll
|
|
||||||
elif hasattr(select, "kqueue"):
|
|
||||||
# Python 2.6+ on BSD or Mac
|
|
||||||
_poll = _KQueue
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
# Linux systems with our C module installed
|
|
||||||
from tornado import epoll
|
|
||||||
_poll = _EPoll
|
|
||||||
except Exception:
|
|
||||||
# All other systems
|
|
||||||
import sys
|
|
||||||
if "linux" in sys.platform:
|
|
||||||
gen_log.warning("epoll module not found; using select()")
|
|
||||||
_poll = _Select
|
|
||||||
|
|
|
@ -4,6 +4,9 @@ from __future__ import absolute_import, division, with_statement
|
||||||
import logging
|
import logging
|
||||||
import textwrap
|
import textwrap
|
||||||
import sys
|
import sys
|
||||||
|
from tornado.httpclient import AsyncHTTPClient
|
||||||
|
from tornado.ioloop import IOLoop
|
||||||
|
from tornado.options import define
|
||||||
from tornado.test.util import unittest
|
from tornado.test.util import unittest
|
||||||
|
|
||||||
TEST_MODULES = [
|
TEST_MODULES = [
|
||||||
|
@ -76,6 +79,11 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
logging.getLogger("tornado.access").setLevel(logging.CRITICAL)
|
logging.getLogger("tornado.access").setLevel(logging.CRITICAL)
|
||||||
|
|
||||||
|
define('httpclient', type=str, default=None,
|
||||||
|
callback=AsyncHTTPClient.configure)
|
||||||
|
define('ioloop', type=str, default=None,
|
||||||
|
callback=IOLoop.configure)
|
||||||
|
|
||||||
import tornado.testing
|
import tornado.testing
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
if sys.version_info >= (3, 2):
|
if sys.version_info >= (3, 2):
|
||||||
|
|
|
@ -471,9 +471,6 @@ def main(**kwargs):
|
||||||
"""
|
"""
|
||||||
from tornado.options import define, options, parse_command_line
|
from tornado.options import define, options, parse_command_line
|
||||||
|
|
||||||
define('autoreload', type=bool, default=False,
|
|
||||||
help="DEPRECATED: use tornado.autoreload.main instead")
|
|
||||||
define('httpclient', type=str, default=None)
|
|
||||||
define('exception_on_interrupt', type=bool, default=True,
|
define('exception_on_interrupt', type=bool, default=True,
|
||||||
help=("If true (default), ctrl-c raises a KeyboardInterrupt "
|
help=("If true (default), ctrl-c raises a KeyboardInterrupt "
|
||||||
"exception. This prints a stack trace but cannot interrupt "
|
"exception. This prints a stack trace but cannot interrupt "
|
||||||
|
@ -489,10 +486,6 @@ def main(**kwargs):
|
||||||
|
|
||||||
argv = [sys.argv[0]] + parse_command_line(sys.argv)
|
argv = [sys.argv[0]] + parse_command_line(sys.argv)
|
||||||
|
|
||||||
if options.httpclient:
|
|
||||||
from tornado.httpclient import AsyncHTTPClient
|
|
||||||
AsyncHTTPClient.configure(options.httpclient)
|
|
||||||
|
|
||||||
if not options.exception_on_interrupt:
|
if not options.exception_on_interrupt:
|
||||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||||
|
|
||||||
|
@ -526,11 +519,7 @@ def main(**kwargs):
|
||||||
gen_log.info('PASS')
|
gen_log.info('PASS')
|
||||||
else:
|
else:
|
||||||
gen_log.error('FAIL')
|
gen_log.error('FAIL')
|
||||||
if not options.autoreload:
|
|
||||||
raise
|
raise
|
||||||
if options.autoreload:
|
|
||||||
import tornado.autoreload
|
|
||||||
tornado.autoreload.wait()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
11
tox.ini
11
tox.ini
|
@ -74,6 +74,17 @@ deps =
|
||||||
twisted>=11.1.0
|
twisted>=11.1.0
|
||||||
commands = python -m tornado.test.runtests --httpclient=tornado.curl_httpclient.CurlAsyncHTTPClient {posargs:}
|
commands = python -m tornado.test.runtests --httpclient=tornado.curl_httpclient.CurlAsyncHTTPClient {posargs:}
|
||||||
|
|
||||||
|
[testenv:py27-select]
|
||||||
|
# Same as py27-full, but runs the tests with the select IOLoop.
|
||||||
|
# The other tests will run with the most platform-appropriate implementation,
|
||||||
|
# but this one is the lowest common denominator and should work anywhere.
|
||||||
|
basepython = python2.7
|
||||||
|
deps =
|
||||||
|
futures
|
||||||
|
pycurl
|
||||||
|
twisted>=12.0.0
|
||||||
|
commands = python -m tornado.test.runtests --ioloop=tornado.ioloop.SelectIOLoop {posargs:}
|
||||||
|
|
||||||
[testenv:pypy-full]
|
[testenv:pypy-full]
|
||||||
# This configuration works with pypy 1.9. pycurl installs ok but
|
# This configuration works with pypy 1.9. pycurl installs ok but
|
||||||
# curl_httpclient doesn't work. Twisted works most of the time, but
|
# curl_httpclient doesn't work. Twisted works most of the time, but
|
||||||
|
|
|
@ -104,3 +104,18 @@ In progress
|
||||||
argument.
|
argument.
|
||||||
* Keyword arguments to `AsyncHTTPClient.configure` are no longer used
|
* Keyword arguments to `AsyncHTTPClient.configure` are no longer used
|
||||||
when instantiating an implementation subclass directly.
|
when instantiating an implementation subclass directly.
|
||||||
|
* The `IOLoop` poller implementations (``select``, ``epoll``, ``kqueue``)
|
||||||
|
are now available as distinct subclasses of `IOLoop`. Instantiating
|
||||||
|
`IOLoop` will continue to automatically choose the best available
|
||||||
|
implementation.
|
||||||
|
* `IOLoop` now has a static ``configure`` method like the one on
|
||||||
|
`AsyncHTTPClient`, which can be used to select an IOLoop implementation
|
||||||
|
other than the default.
|
||||||
|
* The deprecated ``--autoreload`` option of `tornado.testing.main` has
|
||||||
|
been removed. Use ``python -m tornado.autoreload`` as a prefix command
|
||||||
|
instead.
|
||||||
|
* The ``--httpclient`` option of `tornado.testing.main` has been moved
|
||||||
|
to `tornado.test.runtests` so as not to pollute the application
|
||||||
|
option namespace. The `tornado.options` module's new callback
|
||||||
|
support now makes it easy to add options from a wrapper script
|
||||||
|
instead of putting all possible options in `tornado.testing.main`.
|
||||||
|
|
Loading…
Reference in New Issue