Code import
This commit is contained in:
194
venv/lib/python2.7/site-packages/eventlet/hubs/__init__.py
Normal file
194
venv/lib/python2.7/site-packages/eventlet/hubs/__init__.py
Normal file
@@ -0,0 +1,194 @@
|
||||
import os
|
||||
|
||||
from eventlet import patcher
|
||||
from eventlet.support import greenlets as greenlet, six
|
||||
|
||||
|
||||
__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:
|
||||
|
||||
* epoll
|
||||
* kqueue
|
||||
* 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
|
||||
|
||||
select = patcher.original('select')
|
||||
try:
|
||||
import eventlet.hubs.epolls
|
||||
return eventlet.hubs.epolls
|
||||
except ImportError:
|
||||
try:
|
||||
import eventlet.hubs.kqueue
|
||||
return eventlet.hubs.kqueue
|
||||
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 and contains either '.' or ':'
|
||||
use_hub tries to import the hub using the 'package.subpackage.module:Class'
|
||||
convention, otherwise use_hub looks for a matching setuptools entry point
|
||||
in the 'eventlet.hubs' group to load or finally 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, six.string_types):
|
||||
assert mod.strip(), "Need to specify a hub"
|
||||
if '.' in mod or ':' in mod:
|
||||
modulename, _, classname = mod.strip().partition(':')
|
||||
mod = __import__(modulename, globals(), locals(), [classname])
|
||||
if classname:
|
||||
mod = getattr(mod, classname)
|
||||
else:
|
||||
found = False
|
||||
|
||||
# setuptools 5.4.1 test_import_patched_defaults fail
|
||||
# https://github.com/eventlet/eventlet/issues/177
|
||||
try:
|
||||
# try and import pkg_resources ...
|
||||
import pkg_resources
|
||||
except ImportError:
|
||||
# ... but do not depend on it
|
||||
pkg_resources = None
|
||||
if pkg_resources is not None:
|
||||
for entry in pkg_resources.iter_entry_points(
|
||||
group='eventlet.hubs', name=mod):
|
||||
mod, found = entry.load(), True
|
||||
break
|
||||
if not found:
|
||||
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
|
||||
|
||||
|
||||
# Lame middle file import because complex dependencies in import graph
|
||||
from eventlet import timeout
|
||||
|
||||
|
||||
def trampoline(fd, read=None, write=None, timeout=None,
|
||||
timeout_exc=timeout.Timeout,
|
||||
mark_as_closed=None):
|
||||
"""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:
|
||||
def _timeout(exc):
|
||||
# This is only useful to insert debugging
|
||||
current.throw(exc)
|
||||
t = hub.schedule_call_global(timeout, _timeout, timeout_exc)
|
||||
try:
|
||||
if read:
|
||||
listener = hub.add(hub.READ, fileno, current.switch, current.throw, mark_as_closed)
|
||||
elif write:
|
||||
listener = hub.add(hub.WRITE, fileno, current.switch, current.throw, mark_as_closed)
|
||||
try:
|
||||
return hub.switch()
|
||||
finally:
|
||||
hub.remove(listener)
|
||||
finally:
|
||||
if t is not None:
|
||||
t.cancel()
|
||||
|
||||
|
||||
def notify_close(fd):
|
||||
"""
|
||||
A particular file descriptor has been explicitly closed. Register for any
|
||||
waiting listeners to be notified on the next run loop.
|
||||
"""
|
||||
hub = get_hub()
|
||||
hub.notify_close(fd)
|
||||
|
||||
|
||||
def notify_opened(fd):
|
||||
"""
|
||||
Some file descriptors may be closed 'silently' - that is, by the garbage
|
||||
collector, by an external library, etc. When the OS returns a file descriptor
|
||||
from an open call (or something similar), this may be the only indication we
|
||||
have that the FD has been closed and then recycled.
|
||||
We let the hub know that the old file descriptor is dead; any stuck listeners
|
||||
will be disabled and notified in turn.
|
||||
"""
|
||||
hub = get_hub()
|
||||
hub.mark_as_reopened(fd)
|
||||
|
||||
|
||||
class IOClosed(IOError):
|
||||
pass
|
||||
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/__init__.pyc
Normal file
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/__init__.pyc
Normal file
Binary file not shown.
61
venv/lib/python2.7/site-packages/eventlet/hubs/epolls.py
Normal file
61
venv/lib/python2.7/site-packages/eventlet/hubs/epolls.py
Normal file
@@ -0,0 +1,61 @@
|
||||
import errno
|
||||
from eventlet.support import get_errno
|
||||
from eventlet import patcher
|
||||
select = patcher.original("select")
|
||||
if hasattr(select, 'epoll'):
|
||||
epoll = select.epoll
|
||||
else:
|
||||
try:
|
||||
# http://pypi.python.org/pypi/select26/
|
||||
from select26 import epoll
|
||||
except ImportError:
|
||||
try:
|
||||
import epoll as _epoll_mod
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"No epoll implementation found in select module or PYTHONPATH")
|
||||
else:
|
||||
if hasattr(_epoll_mod, 'poll'):
|
||||
epoll = _epoll_mod.poll
|
||||
else:
|
||||
raise ImportError(
|
||||
"You have an old, buggy epoll module in PYTHONPATH."
|
||||
" Install http://pypi.python.org/pypi/python-epoll/"
|
||||
" NOT http://pypi.python.org/pypi/pyepoll/. "
|
||||
" easy_install pyepoll installs the wrong version.")
|
||||
|
||||
from eventlet.hubs.hub import BaseHub
|
||||
from eventlet.hubs import poll
|
||||
from eventlet.hubs.poll import READ, WRITE
|
||||
|
||||
# NOTE: we rely on the fact that the epoll flag constants
|
||||
# are identical in value to the poll constants
|
||||
|
||||
|
||||
class Hub(poll.Hub):
|
||||
def __init__(self, clock=None):
|
||||
BaseHub.__init__(self, clock)
|
||||
self.poll = epoll()
|
||||
try:
|
||||
# modify is required by select.epoll
|
||||
self.modify = self.poll.modify
|
||||
except AttributeError:
|
||||
self.modify = self.poll.register
|
||||
|
||||
def add(self, evtype, fileno, cb, tb, mac):
|
||||
oldlisteners = bool(self.listeners[READ].get(fileno) or
|
||||
self.listeners[WRITE].get(fileno))
|
||||
listener = BaseHub.add(self, evtype, fileno, cb, tb, mac)
|
||||
try:
|
||||
if not oldlisteners:
|
||||
# Means we've added a new listener
|
||||
self.register(fileno, new=True)
|
||||
else:
|
||||
self.register(fileno, new=False)
|
||||
except IOError as ex: # ignore EEXIST, #80
|
||||
if get_errno(ex) != errno.EEXIST:
|
||||
raise
|
||||
return listener
|
||||
|
||||
def do_poll(self, seconds):
|
||||
return self.poll.poll(seconds)
|
||||
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/epolls.pyc
Normal file
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/epolls.pyc
Normal file
Binary file not shown.
483
venv/lib/python2.7/site-packages/eventlet/hubs/hub.py
Normal file
483
venv/lib/python2.7/site-packages/eventlet/hubs/hub.py
Normal file
@@ -0,0 +1,483 @@
|
||||
import errno
|
||||
import heapq
|
||||
import math
|
||||
import signal
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
arm_alarm = None
|
||||
if hasattr(signal, 'setitimer'):
|
||||
def alarm_itimer(seconds):
|
||||
signal.setitimer(signal.ITIMER_REAL, seconds)
|
||||
arm_alarm = alarm_itimer
|
||||
else:
|
||||
try:
|
||||
import itimer
|
||||
arm_alarm = itimer.alarm
|
||||
except ImportError:
|
||||
def alarm_signal(seconds):
|
||||
signal.alarm(math.ceil(seconds))
|
||||
arm_alarm = alarm_signal
|
||||
|
||||
from eventlet.hubs import timer, IOClosed
|
||||
from eventlet.support import greenlets as greenlet, clear_sys_exc_info, monotonic, six
|
||||
|
||||
g_prevent_multiple_readers = True
|
||||
|
||||
READ = "read"
|
||||
WRITE = "write"
|
||||
|
||||
|
||||
def closed_callback(fileno):
|
||||
""" Used to de-fang a callback that may be triggered by a loop in BaseHub.wait
|
||||
"""
|
||||
# No-op.
|
||||
pass
|
||||
|
||||
|
||||
class FdListener(object):
|
||||
|
||||
def __init__(self, evtype, fileno, cb, tb, mark_as_closed):
|
||||
""" The following are required:
|
||||
cb - the standard callback, which will switch into the
|
||||
listening greenlet to indicate that the event waited upon
|
||||
is ready
|
||||
tb - a 'throwback'. This is typically greenlet.throw, used
|
||||
to raise a signal into the target greenlet indicating that
|
||||
an event was obsoleted by its underlying filehandle being
|
||||
repurposed.
|
||||
mark_as_closed - if any listener is obsoleted, this is called
|
||||
(in the context of some other client greenlet) to alert
|
||||
underlying filehandle-wrapping objects that they've been
|
||||
closed.
|
||||
"""
|
||||
assert (evtype is READ or evtype is WRITE)
|
||||
self.evtype = evtype
|
||||
self.fileno = fileno
|
||||
self.cb = cb
|
||||
self.tb = tb
|
||||
self.mark_as_closed = mark_as_closed
|
||||
self.spent = False
|
||||
self.greenlet = greenlet.getcurrent()
|
||||
|
||||
def __repr__(self):
|
||||
return "%s(%r, %r, %r, %r)" % (type(self).__name__, self.evtype, self.fileno,
|
||||
self.cb, self.tb)
|
||||
__str__ = __repr__
|
||||
|
||||
def defang(self):
|
||||
self.cb = closed_callback
|
||||
if self.mark_as_closed is not None:
|
||||
self.mark_as_closed()
|
||||
self.spent = True
|
||||
|
||||
|
||||
noop = FdListener(READ, 0, lambda x: None, lambda x: None, None)
|
||||
|
||||
|
||||
# in debug mode, track the call site that created the listener
|
||||
|
||||
|
||||
class DebugListener(FdListener):
|
||||
|
||||
def __init__(self, evtype, fileno, cb, tb, mark_as_closed):
|
||||
self.where_called = traceback.format_stack()
|
||||
self.greenlet = greenlet.getcurrent()
|
||||
super(DebugListener, self).__init__(evtype, fileno, cb, tb, mark_as_closed)
|
||||
|
||||
def __repr__(self):
|
||||
return "DebugListener(%r, %r, %r, %r, %r, %r)\n%sEndDebugFdListener" % (
|
||||
self.evtype,
|
||||
self.fileno,
|
||||
self.cb,
|
||||
self.tb,
|
||||
self.mark_as_closed,
|
||||
self.greenlet,
|
||||
''.join(self.where_called))
|
||||
__str__ = __repr__
|
||||
|
||||
|
||||
def alarm_handler(signum, frame):
|
||||
import inspect
|
||||
raise RuntimeError("Blocking detector ALARMED at" + str(inspect.getframeinfo(frame)))
|
||||
|
||||
|
||||
class BaseHub(object):
|
||||
""" Base hub class for easing the implementation of subclasses that are
|
||||
specific to a particular underlying event architecture. """
|
||||
|
||||
SYSTEM_EXCEPTIONS = (KeyboardInterrupt, SystemExit)
|
||||
|
||||
READ = READ
|
||||
WRITE = WRITE
|
||||
|
||||
def __init__(self, clock=None):
|
||||
self.listeners = {READ: {}, WRITE: {}}
|
||||
self.secondaries = {READ: {}, WRITE: {}}
|
||||
self.closed = []
|
||||
|
||||
if clock is None:
|
||||
clock = monotonic.monotonic
|
||||
self.clock = clock
|
||||
|
||||
self.greenlet = greenlet.greenlet(self.run)
|
||||
self.stopping = False
|
||||
self.running = False
|
||||
self.timers = []
|
||||
self.next_timers = []
|
||||
self.lclass = FdListener
|
||||
self.timers_canceled = 0
|
||||
self.debug_exceptions = True
|
||||
self.debug_blocking = False
|
||||
self.debug_blocking_resolution = 1
|
||||
|
||||
def block_detect_pre(self):
|
||||
# shortest alarm we can possibly raise is one second
|
||||
tmp = signal.signal(signal.SIGALRM, alarm_handler)
|
||||
if tmp != alarm_handler:
|
||||
self._old_signal_handler = tmp
|
||||
|
||||
arm_alarm(self.debug_blocking_resolution)
|
||||
|
||||
def block_detect_post(self):
|
||||
if (hasattr(self, "_old_signal_handler") and
|
||||
self._old_signal_handler):
|
||||
signal.signal(signal.SIGALRM, self._old_signal_handler)
|
||||
signal.alarm(0)
|
||||
|
||||
def add(self, evtype, fileno, cb, tb, mark_as_closed):
|
||||
""" Signals an intent to or write a particular file descriptor.
|
||||
|
||||
The *evtype* argument is either the constant READ or WRITE.
|
||||
|
||||
The *fileno* argument is the file number of the file of interest.
|
||||
|
||||
The *cb* argument is the callback which will be called when the file
|
||||
is ready for reading/writing.
|
||||
|
||||
The *tb* argument is the throwback used to signal (into the greenlet)
|
||||
that the file was closed.
|
||||
|
||||
The *mark_as_closed* is used in the context of the event hub to
|
||||
prepare a Python object as being closed, pre-empting further
|
||||
close operations from accidentally shutting down the wrong OS thread.
|
||||
"""
|
||||
listener = self.lclass(evtype, fileno, cb, tb, mark_as_closed)
|
||||
bucket = self.listeners[evtype]
|
||||
if fileno in bucket:
|
||||
if g_prevent_multiple_readers:
|
||||
raise RuntimeError(
|
||||
"Second simultaneous %s on fileno %s "
|
||||
"detected. Unless you really know what you're doing, "
|
||||
"make sure that only one greenthread can %s any "
|
||||
"particular socket. Consider using a pools.Pool. "
|
||||
"If you do know what you're doing and want to disable "
|
||||
"this error, call "
|
||||
"eventlet.debug.hub_prevent_multiple_readers(False) - MY THREAD=%s; "
|
||||
"THAT THREAD=%s" % (
|
||||
evtype, fileno, evtype, cb, bucket[fileno]))
|
||||
# store off the second listener in another structure
|
||||
self.secondaries[evtype].setdefault(fileno, []).append(listener)
|
||||
else:
|
||||
bucket[fileno] = listener
|
||||
return listener
|
||||
|
||||
def _obsolete(self, fileno):
|
||||
""" We've received an indication that 'fileno' has been obsoleted.
|
||||
Any current listeners must be defanged, and notifications to
|
||||
their greenlets queued up to send.
|
||||
"""
|
||||
found = False
|
||||
for evtype, bucket in six.iteritems(self.secondaries):
|
||||
if fileno in bucket:
|
||||
for listener in bucket[fileno]:
|
||||
found = True
|
||||
self.closed.append(listener)
|
||||
listener.defang()
|
||||
del bucket[fileno]
|
||||
|
||||
# For the primary listeners, we actually need to call remove,
|
||||
# which may modify the underlying OS polling objects.
|
||||
for evtype, bucket in six.iteritems(self.listeners):
|
||||
if fileno in bucket:
|
||||
listener = bucket[fileno]
|
||||
found = True
|
||||
self.closed.append(listener)
|
||||
self.remove(listener)
|
||||
listener.defang()
|
||||
|
||||
return found
|
||||
|
||||
def notify_close(self, fileno):
|
||||
""" We might want to do something when a fileno is closed.
|
||||
However, currently it suffices to obsolete listeners only
|
||||
when we detect an old fileno being recycled, on open.
|
||||
"""
|
||||
pass
|
||||
|
||||
def remove(self, listener):
|
||||
if listener.spent:
|
||||
# trampoline may trigger this in its finally section.
|
||||
return
|
||||
|
||||
fileno = listener.fileno
|
||||
evtype = listener.evtype
|
||||
self.listeners[evtype].pop(fileno, None)
|
||||
# migrate a secondary listener to be the primary listener
|
||||
if fileno in self.secondaries[evtype]:
|
||||
sec = self.secondaries[evtype].get(fileno, None)
|
||||
if not sec:
|
||||
return
|
||||
self.listeners[evtype][fileno] = sec.pop(0)
|
||||
if not sec:
|
||||
del self.secondaries[evtype][fileno]
|
||||
|
||||
def mark_as_reopened(self, fileno):
|
||||
""" If a file descriptor is returned by the OS as the result of some
|
||||
open call (or equivalent), that signals that it might be being
|
||||
recycled.
|
||||
|
||||
Catch the case where the fd was previously in use.
|
||||
"""
|
||||
self._obsolete(fileno)
|
||||
|
||||
def remove_descriptor(self, fileno):
|
||||
""" Completely remove all listeners for this fileno. For internal use
|
||||
only."""
|
||||
listeners = []
|
||||
listeners.append(self.listeners[READ].pop(fileno, noop))
|
||||
listeners.append(self.listeners[WRITE].pop(fileno, noop))
|
||||
listeners.extend(self.secondaries[READ].pop(fileno, ()))
|
||||
listeners.extend(self.secondaries[WRITE].pop(fileno, ()))
|
||||
for listener in listeners:
|
||||
try:
|
||||
listener.cb(fileno)
|
||||
except Exception:
|
||||
self.squelch_generic_exception(sys.exc_info())
|
||||
|
||||
def close_one(self):
|
||||
""" Triggered from the main run loop. If a listener's underlying FD was
|
||||
closed somehow, throw an exception back to the trampoline, which should
|
||||
be able to manage it appropriately.
|
||||
"""
|
||||
listener = self.closed.pop()
|
||||
if not listener.greenlet.dead:
|
||||
# There's no point signalling a greenlet that's already dead.
|
||||
listener.tb(IOClosed(errno.ENOTCONN, "Operation on closed file"))
|
||||
|
||||
def ensure_greenlet(self):
|
||||
if self.greenlet.dead:
|
||||
# create new greenlet sharing same parent as original
|
||||
new = greenlet.greenlet(self.run, self.greenlet.parent)
|
||||
# need to assign as parent of old greenlet
|
||||
# for those greenlets that are currently
|
||||
# children of the dead hub and may subsequently
|
||||
# exit without further switching to hub.
|
||||
self.greenlet.parent = new
|
||||
self.greenlet = new
|
||||
|
||||
def switch(self):
|
||||
cur = greenlet.getcurrent()
|
||||
assert cur is not self.greenlet, 'Cannot switch to MAINLOOP from MAINLOOP'
|
||||
switch_out = getattr(cur, 'switch_out', None)
|
||||
if switch_out is not None:
|
||||
try:
|
||||
switch_out()
|
||||
except:
|
||||
self.squelch_generic_exception(sys.exc_info())
|
||||
self.ensure_greenlet()
|
||||
try:
|
||||
if self.greenlet.parent is not cur:
|
||||
cur.parent = self.greenlet
|
||||
except ValueError:
|
||||
pass # gets raised if there is a greenlet parent cycle
|
||||
clear_sys_exc_info()
|
||||
return self.greenlet.switch()
|
||||
|
||||
def squelch_exception(self, fileno, exc_info):
|
||||
traceback.print_exception(*exc_info)
|
||||
sys.stderr.write("Removing descriptor: %r\n" % (fileno,))
|
||||
sys.stderr.flush()
|
||||
try:
|
||||
self.remove_descriptor(fileno)
|
||||
except Exception as e:
|
||||
sys.stderr.write("Exception while removing descriptor! %r\n" % (e,))
|
||||
sys.stderr.flush()
|
||||
|
||||
def wait(self, seconds=None):
|
||||
raise NotImplementedError("Implement this in a subclass")
|
||||
|
||||
def default_sleep(self):
|
||||
return 60.0
|
||||
|
||||
def sleep_until(self):
|
||||
t = self.timers
|
||||
if not t:
|
||||
return None
|
||||
return t[0][0]
|
||||
|
||||
def run(self, *a, **kw):
|
||||
"""Run the runloop until abort is called.
|
||||
"""
|
||||
# accept and discard variable arguments because they will be
|
||||
# supplied if other greenlets have run and exited before the
|
||||
# hub's greenlet gets a chance to run
|
||||
if self.running:
|
||||
raise RuntimeError("Already running!")
|
||||
try:
|
||||
self.running = True
|
||||
self.stopping = False
|
||||
while not self.stopping:
|
||||
while self.closed:
|
||||
# We ditch all of these first.
|
||||
self.close_one()
|
||||
self.prepare_timers()
|
||||
if self.debug_blocking:
|
||||
self.block_detect_pre()
|
||||
self.fire_timers(self.clock())
|
||||
if self.debug_blocking:
|
||||
self.block_detect_post()
|
||||
self.prepare_timers()
|
||||
wakeup_when = self.sleep_until()
|
||||
if wakeup_when is None:
|
||||
sleep_time = self.default_sleep()
|
||||
else:
|
||||
sleep_time = wakeup_when - self.clock()
|
||||
if sleep_time > 0:
|
||||
self.wait(sleep_time)
|
||||
else:
|
||||
self.wait(0)
|
||||
else:
|
||||
self.timers_canceled = 0
|
||||
del self.timers[:]
|
||||
del self.next_timers[:]
|
||||
finally:
|
||||
self.running = False
|
||||
self.stopping = False
|
||||
|
||||
def abort(self, wait=False):
|
||||
"""Stop the runloop. If run is executing, it will exit after
|
||||
completing the next runloop iteration.
|
||||
|
||||
Set *wait* to True to cause abort to switch to the hub immediately and
|
||||
wait until it's finished processing. Waiting for the hub will only
|
||||
work from the main greenthread; all other greenthreads will become
|
||||
unreachable.
|
||||
"""
|
||||
if self.running:
|
||||
self.stopping = True
|
||||
if wait:
|
||||
assert self.greenlet is not greenlet.getcurrent(
|
||||
), "Can't abort with wait from inside the hub's greenlet."
|
||||
# schedule an immediate timer just so the hub doesn't sleep
|
||||
self.schedule_call_global(0, lambda: None)
|
||||
# switch to it; when done the hub will switch back to its parent,
|
||||
# the main greenlet
|
||||
self.switch()
|
||||
|
||||
def squelch_generic_exception(self, exc_info):
|
||||
if self.debug_exceptions:
|
||||
traceback.print_exception(*exc_info)
|
||||
sys.stderr.flush()
|
||||
clear_sys_exc_info()
|
||||
|
||||
def squelch_timer_exception(self, timer, exc_info):
|
||||
if self.debug_exceptions:
|
||||
traceback.print_exception(*exc_info)
|
||||
sys.stderr.flush()
|
||||
clear_sys_exc_info()
|
||||
|
||||
def add_timer(self, timer):
|
||||
scheduled_time = self.clock() + timer.seconds
|
||||
self.next_timers.append((scheduled_time, timer))
|
||||
return scheduled_time
|
||||
|
||||
def timer_canceled(self, timer):
|
||||
self.timers_canceled += 1
|
||||
len_timers = len(self.timers) + len(self.next_timers)
|
||||
if len_timers > 1000 and len_timers / 2 <= self.timers_canceled:
|
||||
self.timers_canceled = 0
|
||||
self.timers = [t for t in self.timers if not t[1].called]
|
||||
self.next_timers = [t for t in self.next_timers if not t[1].called]
|
||||
heapq.heapify(self.timers)
|
||||
|
||||
def prepare_timers(self):
|
||||
heappush = heapq.heappush
|
||||
t = self.timers
|
||||
for item in self.next_timers:
|
||||
if item[1].called:
|
||||
self.timers_canceled -= 1
|
||||
else:
|
||||
heappush(t, item)
|
||||
del self.next_timers[:]
|
||||
|
||||
def schedule_call_local(self, seconds, cb, *args, **kw):
|
||||
"""Schedule a callable to be called after 'seconds' seconds have
|
||||
elapsed. Cancel the timer if greenlet has exited.
|
||||
seconds: The number of seconds to wait.
|
||||
cb: The callable to call after the given time.
|
||||
*args: Arguments to pass to the callable when called.
|
||||
**kw: Keyword arguments to pass to the callable when called.
|
||||
"""
|
||||
t = timer.LocalTimer(seconds, cb, *args, **kw)
|
||||
self.add_timer(t)
|
||||
return t
|
||||
|
||||
def schedule_call_global(self, seconds, cb, *args, **kw):
|
||||
"""Schedule a callable to be called after 'seconds' seconds have
|
||||
elapsed. The timer will NOT be canceled if the current greenlet has
|
||||
exited before the timer fires.
|
||||
seconds: The number of seconds to wait.
|
||||
cb: The callable to call after the given time.
|
||||
*args: Arguments to pass to the callable when called.
|
||||
**kw: Keyword arguments to pass to the callable when called.
|
||||
"""
|
||||
t = timer.Timer(seconds, cb, *args, **kw)
|
||||
self.add_timer(t)
|
||||
return t
|
||||
|
||||
def fire_timers(self, when):
|
||||
t = self.timers
|
||||
heappop = heapq.heappop
|
||||
|
||||
while t:
|
||||
next = t[0]
|
||||
|
||||
exp = next[0]
|
||||
timer = next[1]
|
||||
|
||||
if when < exp:
|
||||
break
|
||||
|
||||
heappop(t)
|
||||
|
||||
try:
|
||||
if timer.called:
|
||||
self.timers_canceled -= 1
|
||||
else:
|
||||
timer()
|
||||
except self.SYSTEM_EXCEPTIONS:
|
||||
raise
|
||||
except:
|
||||
self.squelch_timer_exception(timer, sys.exc_info())
|
||||
clear_sys_exc_info()
|
||||
|
||||
# for debugging:
|
||||
|
||||
def get_readers(self):
|
||||
return self.listeners[READ].values()
|
||||
|
||||
def get_writers(self):
|
||||
return self.listeners[WRITE].values()
|
||||
|
||||
def get_timers_count(hub):
|
||||
return len(hub.timers) + len(hub.next_timers)
|
||||
|
||||
def set_debug_listeners(self, value):
|
||||
if value:
|
||||
self.lclass = DebugListener
|
||||
else:
|
||||
self.lclass = FdListener
|
||||
|
||||
def set_timer_exceptions(self, value):
|
||||
self.debug_exceptions = value
|
||||
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/hub.pyc
Normal file
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/hub.pyc
Normal file
Binary file not shown.
114
venv/lib/python2.7/site-packages/eventlet/hubs/kqueue.py
Normal file
114
venv/lib/python2.7/site-packages/eventlet/hubs/kqueue.py
Normal file
@@ -0,0 +1,114 @@
|
||||
import os
|
||||
import sys
|
||||
from eventlet import patcher, support
|
||||
from eventlet.support import six
|
||||
select = patcher.original('select')
|
||||
time = patcher.original('time')
|
||||
|
||||
from eventlet.hubs.hub import BaseHub, READ, WRITE, noop
|
||||
|
||||
|
||||
if getattr(select, 'kqueue', None) is None:
|
||||
raise ImportError('No kqueue implementation found in select module')
|
||||
|
||||
|
||||
FILTERS = {READ: select.KQ_FILTER_READ,
|
||||
WRITE: select.KQ_FILTER_WRITE}
|
||||
|
||||
|
||||
class Hub(BaseHub):
|
||||
MAX_EVENTS = 100
|
||||
|
||||
def __init__(self, clock=None):
|
||||
super(Hub, self).__init__(clock)
|
||||
self._events = {}
|
||||
self._init_kqueue()
|
||||
|
||||
def _init_kqueue(self):
|
||||
self.kqueue = select.kqueue()
|
||||
self._pid = os.getpid()
|
||||
|
||||
def _reinit_kqueue(self):
|
||||
self.kqueue.close()
|
||||
self._init_kqueue()
|
||||
kqueue = self.kqueue
|
||||
events = [e for i in six.itervalues(self._events)
|
||||
for e in six.itervalues(i)]
|
||||
kqueue.control(events, 0, 0)
|
||||
|
||||
def _control(self, events, max_events, timeout):
|
||||
try:
|
||||
return self.kqueue.control(events, max_events, timeout)
|
||||
except (OSError, IOError):
|
||||
# have we forked?
|
||||
if os.getpid() != self._pid:
|
||||
self._reinit_kqueue()
|
||||
return self.kqueue.control(events, max_events, timeout)
|
||||
raise
|
||||
|
||||
def add(self, evtype, fileno, cb, tb, mac):
|
||||
listener = super(Hub, self).add(evtype, fileno, cb, tb, mac)
|
||||
events = self._events.setdefault(fileno, {})
|
||||
if evtype not in events:
|
||||
try:
|
||||
event = select.kevent(fileno, FILTERS.get(evtype), select.KQ_EV_ADD)
|
||||
self._control([event], 0, 0)
|
||||
events[evtype] = event
|
||||
except ValueError:
|
||||
super(Hub, self).remove(listener)
|
||||
raise
|
||||
return listener
|
||||
|
||||
def _delete_events(self, events):
|
||||
del_events = [
|
||||
select.kevent(e.ident, e.filter, select.KQ_EV_DELETE)
|
||||
for e in events
|
||||
]
|
||||
self._control(del_events, 0, 0)
|
||||
|
||||
def remove(self, listener):
|
||||
super(Hub, self).remove(listener)
|
||||
evtype = listener.evtype
|
||||
fileno = listener.fileno
|
||||
if not self.listeners[evtype].get(fileno):
|
||||
event = self._events[fileno].pop(evtype, None)
|
||||
if event is None:
|
||||
return
|
||||
try:
|
||||
self._delete_events((event,))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def remove_descriptor(self, fileno):
|
||||
super(Hub, self).remove_descriptor(fileno)
|
||||
try:
|
||||
events = self._events.pop(fileno).values()
|
||||
self._delete_events(events)
|
||||
except KeyError:
|
||||
pass
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def wait(self, seconds=None):
|
||||
readers = self.listeners[READ]
|
||||
writers = self.listeners[WRITE]
|
||||
|
||||
if not readers and not writers:
|
||||
if seconds:
|
||||
time.sleep(seconds)
|
||||
return
|
||||
result = self._control([], self.MAX_EVENTS, seconds)
|
||||
SYSTEM_EXCEPTIONS = self.SYSTEM_EXCEPTIONS
|
||||
for event in result:
|
||||
fileno = event.ident
|
||||
evfilt = event.filter
|
||||
try:
|
||||
if evfilt == FILTERS[READ]:
|
||||
readers.get(fileno, noop).cb(fileno)
|
||||
if evfilt == FILTERS[WRITE]:
|
||||
writers.get(fileno, noop).cb(fileno)
|
||||
except SYSTEM_EXCEPTIONS:
|
||||
raise
|
||||
except:
|
||||
self.squelch_exception(fileno, sys.exc_info())
|
||||
support.clear_sys_exc_info()
|
||||
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/kqueue.pyc
Normal file
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/kqueue.pyc
Normal file
Binary file not shown.
122
venv/lib/python2.7/site-packages/eventlet/hubs/poll.py
Normal file
122
venv/lib/python2.7/site-packages/eventlet/hubs/poll.py
Normal file
@@ -0,0 +1,122 @@
|
||||
import errno
|
||||
import sys
|
||||
|
||||
from eventlet import patcher
|
||||
select = patcher.original('select')
|
||||
time = patcher.original('time')
|
||||
|
||||
from eventlet.hubs.hub import BaseHub, READ, WRITE, noop
|
||||
from eventlet.support import get_errno, clear_sys_exc_info
|
||||
|
||||
EXC_MASK = select.POLLERR | select.POLLHUP
|
||||
READ_MASK = select.POLLIN | select.POLLPRI
|
||||
WRITE_MASK = select.POLLOUT
|
||||
|
||||
|
||||
class Hub(BaseHub):
|
||||
def __init__(self, clock=None):
|
||||
super(Hub, self).__init__(clock)
|
||||
self.poll = select.poll()
|
||||
# poll.modify is new to 2.6
|
||||
try:
|
||||
self.modify = self.poll.modify
|
||||
except AttributeError:
|
||||
self.modify = self.poll.register
|
||||
|
||||
def add(self, evtype, fileno, cb, tb, mac):
|
||||
listener = super(Hub, self).add(evtype, fileno, cb, tb, mac)
|
||||
self.register(fileno, new=True)
|
||||
return listener
|
||||
|
||||
def remove(self, listener):
|
||||
super(Hub, self).remove(listener)
|
||||
self.register(listener.fileno)
|
||||
|
||||
def register(self, fileno, new=False):
|
||||
mask = 0
|
||||
if self.listeners[READ].get(fileno):
|
||||
mask |= READ_MASK | EXC_MASK
|
||||
if self.listeners[WRITE].get(fileno):
|
||||
mask |= WRITE_MASK | EXC_MASK
|
||||
try:
|
||||
if mask:
|
||||
if new:
|
||||
self.poll.register(fileno, mask)
|
||||
else:
|
||||
try:
|
||||
self.modify(fileno, mask)
|
||||
except (IOError, OSError):
|
||||
self.poll.register(fileno, mask)
|
||||
else:
|
||||
try:
|
||||
self.poll.unregister(fileno)
|
||||
except (KeyError, IOError, OSError):
|
||||
# raised if we try to remove a fileno that was
|
||||
# already removed/invalid
|
||||
pass
|
||||
except ValueError:
|
||||
# fileno is bad, issue 74
|
||||
self.remove_descriptor(fileno)
|
||||
raise
|
||||
|
||||
def remove_descriptor(self, fileno):
|
||||
super(Hub, self).remove_descriptor(fileno)
|
||||
try:
|
||||
self.poll.unregister(fileno)
|
||||
except (KeyError, ValueError, IOError, OSError):
|
||||
# raised if we try to remove a fileno that was
|
||||
# already removed/invalid
|
||||
pass
|
||||
|
||||
def do_poll(self, seconds):
|
||||
# poll.poll expects integral milliseconds
|
||||
return self.poll.poll(int(seconds * 1000.0))
|
||||
|
||||
def wait(self, seconds=None):
|
||||
readers = self.listeners[READ]
|
||||
writers = self.listeners[WRITE]
|
||||
|
||||
if not readers and not writers:
|
||||
if seconds:
|
||||
time.sleep(seconds)
|
||||
return
|
||||
try:
|
||||
presult = self.do_poll(seconds)
|
||||
except (IOError, select.error) as e:
|
||||
if get_errno(e) == errno.EINTR:
|
||||
return
|
||||
raise
|
||||
SYSTEM_EXCEPTIONS = self.SYSTEM_EXCEPTIONS
|
||||
|
||||
if self.debug_blocking:
|
||||
self.block_detect_pre()
|
||||
|
||||
# Accumulate the listeners to call back to prior to
|
||||
# triggering any of them. This is to keep the set
|
||||
# of callbacks in sync with the events we've just
|
||||
# polled for. It prevents one handler from invalidating
|
||||
# another.
|
||||
callbacks = set()
|
||||
for fileno, event in presult:
|
||||
if event & READ_MASK:
|
||||
callbacks.add((readers.get(fileno, noop), fileno))
|
||||
if event & WRITE_MASK:
|
||||
callbacks.add((writers.get(fileno, noop), fileno))
|
||||
if event & select.POLLNVAL:
|
||||
self.remove_descriptor(fileno)
|
||||
continue
|
||||
if event & EXC_MASK:
|
||||
callbacks.add((readers.get(fileno, noop), fileno))
|
||||
callbacks.add((writers.get(fileno, noop), fileno))
|
||||
|
||||
for listener, fileno in callbacks:
|
||||
try:
|
||||
listener.cb(fileno)
|
||||
except SYSTEM_EXCEPTIONS:
|
||||
raise
|
||||
except:
|
||||
self.squelch_exception(fileno, sys.exc_info())
|
||||
clear_sys_exc_info()
|
||||
|
||||
if self.debug_blocking:
|
||||
self.block_detect_post()
|
||||
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/poll.pyc
Normal file
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/poll.pyc
Normal file
Binary file not shown.
178
venv/lib/python2.7/site-packages/eventlet/hubs/pyevent.py
Normal file
178
venv/lib/python2.7/site-packages/eventlet/hubs/pyevent.py
Normal file
@@ -0,0 +1,178 @@
|
||||
import sys
|
||||
import traceback
|
||||
import event
|
||||
import types
|
||||
|
||||
from eventlet.support import greenlets as greenlet, six
|
||||
from eventlet.hubs.hub import BaseHub, READ, WRITE
|
||||
|
||||
|
||||
class event_wrapper(object):
|
||||
|
||||
def __init__(self, impl=None, seconds=None):
|
||||
self.impl = impl
|
||||
self.seconds = seconds
|
||||
|
||||
def __repr__(self):
|
||||
if self.impl is not None:
|
||||
return repr(self.impl)
|
||||
else:
|
||||
return object.__repr__(self)
|
||||
|
||||
def __str__(self):
|
||||
if self.impl is not None:
|
||||
return str(self.impl)
|
||||
else:
|
||||
return object.__str__(self)
|
||||
|
||||
def cancel(self):
|
||||
if self.impl is not None:
|
||||
self.impl.delete()
|
||||
self.impl = None
|
||||
|
||||
@property
|
||||
def pending(self):
|
||||
return bool(self.impl and self.impl.pending())
|
||||
|
||||
|
||||
class Hub(BaseHub):
|
||||
|
||||
SYSTEM_EXCEPTIONS = (KeyboardInterrupt, SystemExit)
|
||||
|
||||
def __init__(self):
|
||||
super(Hub, self).__init__()
|
||||
event.init()
|
||||
|
||||
self.signal_exc_info = None
|
||||
self.signal(
|
||||
2,
|
||||
lambda signalnum, frame: self.greenlet.parent.throw(KeyboardInterrupt))
|
||||
self.events_to_add = []
|
||||
|
||||
def dispatch(self):
|
||||
loop = event.loop
|
||||
while True:
|
||||
for e in self.events_to_add:
|
||||
if e is not None and e.impl is not None and e.seconds is not None:
|
||||
e.impl.add(e.seconds)
|
||||
e.seconds = None
|
||||
self.events_to_add = []
|
||||
result = loop()
|
||||
|
||||
if getattr(event, '__event_exc', None) is not None:
|
||||
# only have to do this because of bug in event.loop
|
||||
t = getattr(event, '__event_exc')
|
||||
setattr(event, '__event_exc', None)
|
||||
assert getattr(event, '__event_exc') is None
|
||||
six.reraise(t[0], t[1], t[2])
|
||||
|
||||
if result != 0:
|
||||
return result
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
try:
|
||||
self.dispatch()
|
||||
except greenlet.GreenletExit:
|
||||
break
|
||||
except self.SYSTEM_EXCEPTIONS:
|
||||
raise
|
||||
except:
|
||||
if self.signal_exc_info is not None:
|
||||
self.schedule_call_global(
|
||||
0, greenlet.getcurrent().parent.throw, *self.signal_exc_info)
|
||||
self.signal_exc_info = None
|
||||
else:
|
||||
self.squelch_timer_exception(None, sys.exc_info())
|
||||
|
||||
def abort(self, wait=True):
|
||||
self.schedule_call_global(0, self.greenlet.throw, greenlet.GreenletExit)
|
||||
if wait:
|
||||
assert self.greenlet is not greenlet.getcurrent(
|
||||
), "Can't abort with wait from inside the hub's greenlet."
|
||||
self.switch()
|
||||
|
||||
def _getrunning(self):
|
||||
return bool(self.greenlet)
|
||||
|
||||
def _setrunning(self, value):
|
||||
pass # exists for compatibility with BaseHub
|
||||
running = property(_getrunning, _setrunning)
|
||||
|
||||
def add(self, evtype, fileno, real_cb, real_tb, mac):
|
||||
# this is stupid: pyevent won't call a callback unless it's a function,
|
||||
# so we have to force it to be one here
|
||||
if isinstance(real_cb, types.BuiltinMethodType):
|
||||
def cb(_d):
|
||||
real_cb(_d)
|
||||
else:
|
||||
cb = real_cb
|
||||
|
||||
if evtype is READ:
|
||||
evt = event.read(fileno, cb, fileno)
|
||||
elif evtype is WRITE:
|
||||
evt = event.write(fileno, cb, fileno)
|
||||
|
||||
return super(Hub, self).add(evtype, fileno, evt, real_tb, mac)
|
||||
|
||||
def signal(self, signalnum, handler):
|
||||
def wrapper():
|
||||
try:
|
||||
handler(signalnum, None)
|
||||
except:
|
||||
self.signal_exc_info = sys.exc_info()
|
||||
event.abort()
|
||||
return event_wrapper(event.signal(signalnum, wrapper))
|
||||
|
||||
def remove(self, listener):
|
||||
super(Hub, self).remove(listener)
|
||||
listener.cb.delete()
|
||||
|
||||
def remove_descriptor(self, fileno):
|
||||
for lcontainer in six.itervalues(self.listeners):
|
||||
listener = lcontainer.pop(fileno, None)
|
||||
if listener:
|
||||
try:
|
||||
listener.cb.delete()
|
||||
except self.SYSTEM_EXCEPTIONS:
|
||||
raise
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
def schedule_call_local(self, seconds, cb, *args, **kwargs):
|
||||
current = greenlet.getcurrent()
|
||||
if current is self.greenlet:
|
||||
return self.schedule_call_global(seconds, cb, *args, **kwargs)
|
||||
event_impl = event.event(_scheduled_call_local, (cb, args, kwargs, current))
|
||||
wrapper = event_wrapper(event_impl, seconds=seconds)
|
||||
self.events_to_add.append(wrapper)
|
||||
return wrapper
|
||||
|
||||
schedule_call = schedule_call_local
|
||||
|
||||
def schedule_call_global(self, seconds, cb, *args, **kwargs):
|
||||
event_impl = event.event(_scheduled_call, (cb, args, kwargs))
|
||||
wrapper = event_wrapper(event_impl, seconds=seconds)
|
||||
self.events_to_add.append(wrapper)
|
||||
return wrapper
|
||||
|
||||
def _version_info(self):
|
||||
baseversion = event.__version__
|
||||
return baseversion
|
||||
|
||||
|
||||
def _scheduled_call(event_impl, handle, evtype, arg):
|
||||
cb, args, kwargs = arg
|
||||
try:
|
||||
cb(*args, **kwargs)
|
||||
finally:
|
||||
event_impl.delete()
|
||||
|
||||
|
||||
def _scheduled_call_local(event_impl, handle, evtype, arg):
|
||||
cb, args, kwargs, caller_greenlet = arg
|
||||
try:
|
||||
if not caller_greenlet.dead:
|
||||
cb(*args, **kwargs)
|
||||
finally:
|
||||
event_impl.delete()
|
||||
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/pyevent.pyc
Normal file
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/pyevent.pyc
Normal file
Binary file not shown.
60
venv/lib/python2.7/site-packages/eventlet/hubs/selects.py
Normal file
60
venv/lib/python2.7/site-packages/eventlet/hubs/selects.py
Normal file
@@ -0,0 +1,60 @@
|
||||
import errno
|
||||
import sys
|
||||
from eventlet import patcher
|
||||
from eventlet.support import get_errno, clear_sys_exc_info
|
||||
select = patcher.original('select')
|
||||
time = patcher.original('time')
|
||||
|
||||
from eventlet.hubs.hub import BaseHub, READ, WRITE, noop
|
||||
|
||||
try:
|
||||
BAD_SOCK = set((errno.EBADF, errno.WSAENOTSOCK))
|
||||
except AttributeError:
|
||||
BAD_SOCK = set((errno.EBADF,))
|
||||
|
||||
|
||||
class Hub(BaseHub):
|
||||
def _remove_bad_fds(self):
|
||||
""" Iterate through fds, removing the ones that are bad per the
|
||||
operating system.
|
||||
"""
|
||||
all_fds = list(self.listeners[READ]) + list(self.listeners[WRITE])
|
||||
for fd in all_fds:
|
||||
try:
|
||||
select.select([fd], [], [], 0)
|
||||
except select.error as e:
|
||||
if get_errno(e) in BAD_SOCK:
|
||||
self.remove_descriptor(fd)
|
||||
|
||||
def wait(self, seconds=None):
|
||||
readers = self.listeners[READ]
|
||||
writers = self.listeners[WRITE]
|
||||
if not readers and not writers:
|
||||
if seconds:
|
||||
time.sleep(seconds)
|
||||
return
|
||||
all_fds = list(readers) + list(writers)
|
||||
try:
|
||||
r, w, er = select.select(readers.keys(), writers.keys(), all_fds, seconds)
|
||||
except select.error as e:
|
||||
if get_errno(e) == errno.EINTR:
|
||||
return
|
||||
elif get_errno(e) in BAD_SOCK:
|
||||
self._remove_bad_fds()
|
||||
return
|
||||
else:
|
||||
raise
|
||||
|
||||
for fileno in er:
|
||||
readers.get(fileno, noop).cb(fileno)
|
||||
writers.get(fileno, noop).cb(fileno)
|
||||
|
||||
for listeners, events in ((readers, r), (writers, w)):
|
||||
for fileno in events:
|
||||
try:
|
||||
listeners.get(fileno, noop).cb(fileno)
|
||||
except self.SYSTEM_EXCEPTIONS:
|
||||
raise
|
||||
except:
|
||||
self.squelch_exception(fileno, sys.exc_info())
|
||||
clear_sys_exc_info()
|
||||
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/selects.pyc
Normal file
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/selects.pyc
Normal file
Binary file not shown.
105
venv/lib/python2.7/site-packages/eventlet/hubs/timer.py
Normal file
105
venv/lib/python2.7/site-packages/eventlet/hubs/timer.py
Normal file
@@ -0,0 +1,105 @@
|
||||
import traceback
|
||||
|
||||
from eventlet.support import greenlets as greenlet, six
|
||||
from eventlet.hubs import get_hub
|
||||
|
||||
""" If true, captures a stack trace for each timer when constructed. This is
|
||||
useful for debugging leaking timers, to find out where the timer was set up. """
|
||||
_g_debug = False
|
||||
|
||||
|
||||
class Timer(object):
|
||||
def __init__(self, seconds, cb, *args, **kw):
|
||||
"""Create a timer.
|
||||
seconds: The minimum number of seconds to wait before calling
|
||||
cb: The callback to call when the timer has expired
|
||||
*args: The arguments to pass to cb
|
||||
**kw: The keyword arguments to pass to cb
|
||||
|
||||
This timer will not be run unless it is scheduled in a runloop by
|
||||
calling timer.schedule() or runloop.add_timer(timer).
|
||||
"""
|
||||
self.seconds = seconds
|
||||
self.tpl = cb, args, kw
|
||||
self.called = False
|
||||
if _g_debug:
|
||||
self.traceback = six.StringIO()
|
||||
traceback.print_stack(file=self.traceback)
|
||||
|
||||
@property
|
||||
def pending(self):
|
||||
return not self.called
|
||||
|
||||
def __repr__(self):
|
||||
secs = getattr(self, 'seconds', None)
|
||||
cb, args, kw = getattr(self, 'tpl', (None, None, None))
|
||||
retval = "Timer(%s, %s, *%s, **%s)" % (
|
||||
secs, cb, args, kw)
|
||||
if _g_debug and hasattr(self, 'traceback'):
|
||||
retval += '\n' + self.traceback.getvalue()
|
||||
return retval
|
||||
|
||||
def copy(self):
|
||||
cb, args, kw = self.tpl
|
||||
return self.__class__(self.seconds, cb, *args, **kw)
|
||||
|
||||
def schedule(self):
|
||||
"""Schedule this timer to run in the current runloop.
|
||||
"""
|
||||
self.called = False
|
||||
self.scheduled_time = get_hub().add_timer(self)
|
||||
return self
|
||||
|
||||
def __call__(self, *args):
|
||||
if not self.called:
|
||||
self.called = True
|
||||
cb, args, kw = self.tpl
|
||||
try:
|
||||
cb(*args, **kw)
|
||||
finally:
|
||||
try:
|
||||
del self.tpl
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def cancel(self):
|
||||
"""Prevent this timer from being called. If the timer has already
|
||||
been called or canceled, has no effect.
|
||||
"""
|
||||
if not self.called:
|
||||
self.called = True
|
||||
get_hub().timer_canceled(self)
|
||||
try:
|
||||
del self.tpl
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# No default ordering in 3.x. heapq uses <
|
||||
# FIXME should full set be added?
|
||||
def __lt__(self, other):
|
||||
return id(self) < id(other)
|
||||
|
||||
|
||||
class LocalTimer(Timer):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.greenlet = greenlet.getcurrent()
|
||||
Timer.__init__(self, *args, **kwargs)
|
||||
|
||||
@property
|
||||
def pending(self):
|
||||
if self.greenlet is None or self.greenlet.dead:
|
||||
return False
|
||||
return not self.called
|
||||
|
||||
def __call__(self, *args):
|
||||
if not self.called:
|
||||
self.called = True
|
||||
if self.greenlet is not None and self.greenlet.dead:
|
||||
return
|
||||
cb, args, kw = self.tpl
|
||||
cb(*args, **kw)
|
||||
|
||||
def cancel(self):
|
||||
self.greenlet = None
|
||||
Timer.cancel(self)
|
||||
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/timer.pyc
Normal file
BIN
venv/lib/python2.7/site-packages/eventlet/hubs/timer.pyc
Normal file
Binary file not shown.
Reference in New Issue
Block a user