131 lines
4.1 KiB
Python
131 lines
4.1 KiB
Python
import sys
|
|
import os
|
|
from eventlet.support import greenlets as greenlet
|
|
from eventlet import patcher
|
|
|
|
__all__ = ["use_hub", "get_hub", "get_default_hub", "trampoline"]
|
|
|
|
threading = patcher.original('threading')
|
|
_threadlocal = threading.local()
|
|
|
|
def get_default_hub():
|
|
"""Select the default hub implementation based on what multiplexing
|
|
libraries are installed. The order that the hubs are tried is:
|
|
|
|
* twistedr
|
|
* epoll
|
|
* poll
|
|
* select
|
|
|
|
It won't automatically select the pyevent hub, because it's not
|
|
python-thread-safe.
|
|
|
|
.. include:: ../../doc/common.txt
|
|
.. note :: |internal|
|
|
"""
|
|
|
|
# pyevent hub disabled for now because it is not thread-safe
|
|
#try:
|
|
# import eventlet.hubs.pyevent
|
|
# return eventlet.hubs.pyevent
|
|
#except:
|
|
# pass
|
|
|
|
if 'twisted.internet.reactor' in sys.modules:
|
|
from eventlet.hubs import twistedr
|
|
return twistedr
|
|
|
|
select = patcher.original('select')
|
|
try:
|
|
import eventlet.hubs.epolls
|
|
return eventlet.hubs.epolls
|
|
except ImportError:
|
|
if hasattr(select, 'poll'):
|
|
import eventlet.hubs.poll
|
|
return eventlet.hubs.poll
|
|
else:
|
|
import eventlet.hubs.selects
|
|
return eventlet.hubs.selects
|
|
|
|
|
|
def use_hub(mod=None):
|
|
"""Use the module *mod*, containing a class called Hub, as the
|
|
event hub. Usually not required; the default hub is usually fine.
|
|
|
|
Mod can be an actual module, a string, or None. If *mod* is a module,
|
|
it uses it directly. If *mod* is a string, use_hub tries to import
|
|
`eventlet.hubs.mod` and use that as the hub module. If *mod* is None,
|
|
use_hub uses the default hub. Only call use_hub during application
|
|
initialization, because it resets the hub's state and any existing
|
|
timers or listeners will never be resumed.
|
|
"""
|
|
if mod is None:
|
|
mod = os.environ.get('EVENTLET_HUB', None)
|
|
if mod is None:
|
|
mod = get_default_hub()
|
|
if hasattr(_threadlocal, 'hub'):
|
|
del _threadlocal.hub
|
|
if isinstance(mod, str):
|
|
assert mod.strip(), "Need to specify a hub"
|
|
mod = __import__('eventlet.hubs.' + mod, globals(), locals(), ['Hub'])
|
|
if hasattr(mod, 'Hub'):
|
|
_threadlocal.Hub = mod.Hub
|
|
else:
|
|
_threadlocal.Hub = mod
|
|
|
|
def get_hub():
|
|
"""Get the current event hub singleton object.
|
|
|
|
.. note :: |internal|
|
|
"""
|
|
try:
|
|
hub = _threadlocal.hub
|
|
except AttributeError:
|
|
try:
|
|
_threadlocal.Hub
|
|
except AttributeError:
|
|
use_hub()
|
|
hub = _threadlocal.hub = _threadlocal.Hub()
|
|
return hub
|
|
|
|
from eventlet import timeout
|
|
def trampoline(fd, read=None, write=None, timeout=None,
|
|
timeout_exc=timeout.Timeout):
|
|
"""Suspend the current coroutine until the given socket object or file
|
|
descriptor is ready to *read*, ready to *write*, or the specified
|
|
*timeout* elapses, depending on arguments specified.
|
|
|
|
To wait for *fd* to be ready to read, pass *read* ``=True``; ready to
|
|
write, pass *write* ``=True``. To specify a timeout, pass the *timeout*
|
|
argument in seconds.
|
|
|
|
If the specified *timeout* elapses before the socket is ready to read or
|
|
write, *timeout_exc* will be raised instead of ``trampoline()``
|
|
returning normally.
|
|
|
|
.. note :: |internal|
|
|
"""
|
|
t = None
|
|
hub = get_hub()
|
|
current = greenlet.getcurrent()
|
|
assert hub.greenlet is not current, 'do not call blocking functions from the mainloop'
|
|
assert not (read and write), 'not allowed to trampoline for reading and writing'
|
|
try:
|
|
fileno = fd.fileno()
|
|
except AttributeError:
|
|
fileno = fd
|
|
if timeout is not None:
|
|
t = hub.schedule_call_global(timeout, current.throw, timeout_exc)
|
|
try:
|
|
if read:
|
|
listener = hub.add(hub.READ, fileno, current.switch)
|
|
elif write:
|
|
listener = hub.add(hub.WRITE, fileno, current.switch)
|
|
try:
|
|
return hub.switch()
|
|
finally:
|
|
hub.remove(listener)
|
|
finally:
|
|
if t is not None:
|
|
t.cancel()
|