def _spawn_startup(cb, args, kw, cancel=None): try: greenlet.getcurrent().parent.switch() cancel = None finally: if cancel is not None: cancel() return cb(*args, **kw)
def switch(self): assert greenlet.getcurrent() is not self.greenlet, \ "Cannot switch from MAINLOOP to MAINLOOP" try: greenlet.getcurrent().parent = self.greenlet except ValueError: pass return self.greenlet.switch()
def _send_tasklet(self, *args): try: t = self._tasklet except AttributeError: t = self._tasklet = greenlet.greenlet(self._tasklet_loop) t.switch() if args: return t.switch((1, greenlet.getcurrent(), args)) else: return t.switch((-1, greenlet.getcurrent(), args))
def start(self): """Schedule the timeout. This is called on construction, so it should not be called explicitly, unless the timer has been cancelled.""" assert not self.pending, \ '%r is already started; to restart it, cancel it first' % self if self.seconds is None: # "fake" timeout (never expires) self.timer = None elif self.exception is None or self.exception is False: # timeout that raises self self.timer = get_hub().schedule_call_global( self.seconds, greenlet.getcurrent().throw, self) else: # regular timeout with user-provided exception self.timer = get_hub().schedule_call_global( self.seconds, greenlet.getcurrent().throw, self.exception) return self
def start(self): """Schedule the timeout. This is called on construction, so it should not be called explicitly, unless the timer has been canceled.""" assert not self.pending, \ '%r is already started; to restart it, cancel it first' % self if self.seconds is None: # "fake" timeout (never expires) self.timer = None elif self.exception is None or isinstance(self.exception, bool): # timeout that raises self self.timer = get_hub().schedule_call_global( self.seconds, greenlet.getcurrent().throw, self) else: # regular timeout with user-provided exception self.timer = get_hub().schedule_call_global( self.seconds, greenlet.getcurrent().throw, self.exception) return self
def current_thread(): g = greenlet.getcurrent() if not g: # Not currently in a greenthread, fall back to standard function return _fixup_thread(__orig_threading.current_thread()) try: active = __threadlocal.active except AttributeError: active = __threadlocal.active = {} try: t = active[id(g)] except KeyError: # Add green thread to active if we can clean it up on exit def cleanup(g): del active[id(g)] try: g.link(cleanup) except AttributeError: # Not a GreenThread type, so there's no way to hook into # the green thread exiting. Fall back to the standard # function then. t = _fixup_thread(__orig_threading.currentThread()) else: t = active[id(g)] = _GreenThread(g) return t
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 wait(self): """Wait until another coroutine calls :meth:`send`. Returns the value the other coroutine passed to :meth:`send`. >>> from eventlet import event >>> import eventlet >>> evt = event.Event() >>> def wait_on(): ... retval = evt.wait() ... print("waited for {0}".format(retval)) >>> _ = eventlet.spawn(wait_on) >>> evt.send('result') >>> eventlet.sleep(0) waited for result Returns immediately if the event has already occured. >>> evt.wait() 'result' """ current = greenlet.getcurrent() if self._result is NOT_USED: self._waiters.add(current) try: return hubs.get_hub().switch() finally: self._waiters.discard(current) if self._exc is not None: current.throw(*self._exc) return self._result
def wait(self): """Wait until another coroutine calls :meth:`send`. Returns the value the other coroutine passed to :meth:`send`. >>> from eventlet import event >>> import eventlet >>> evt = event.Event() >>> def wait_on(): ... retval = evt.wait() ... print "waited for", retval >>> _ = eventlet.spawn(wait_on) >>> evt.send('result') >>> eventlet.sleep(0) waited for result Returns immediately if the event has already occured. >>> evt.wait() 'result' """ current = greenlet.getcurrent() if self._result is NOT_USED: self._waiters.add(current) try: return hubs.get_hub().switch() finally: self._waiters.discard(current) if self._exc is not None: current.throw(*self._exc) return self._result
def g_log(*args): import sys from eventlet.support import greenlets as greenlet g_id = id(greenlet.getcurrent()) if g_id is None: if greenlet.getcurrent().parent is None: ident = "greenlet-main" else: g_id = id(greenlet.getcurrent()) if g_id < 0: g_id += 1 + ((sys.maxint + 1) << 1) ident = "%08X" % (g_id,) else: ident = "greenlet-%d" % (g_id,) print >>sys.stderr, "[%s] %s" % (ident, " ".join(map(str, args)))
def _tasklet_loop(self): deque = self.deque = collections.deque() hub = api.get_hub() current = greenlet.getcurrent() def switch(g, value=None, exc=None): if exc is None: return g.switch(value) else: return g.throw(exc) direction, caller, args = switch(current.parent or current) try: while True: if direction == -1: # waiting to receive if self.balance > 0: sender, args = deque.popleft() hub.schedule_call(0, switch, sender) hub.schedule_call(0, switch, caller, *args) else: deque.append(caller) else: # waiting to send if self.balance < 0: receiver = deque.popleft() hub.schedule_call(0, switch, receiver, *args) hub.schedule_call(0, switch, caller) else: deque.append((caller, args)) self.balance += direction direction, caller, args = hub.switch() finally: deque.clear() del self.deque self.balance = 0
def add(self, evtype, fileno, cb): """ Signals an intent to read 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. """ g = greenlet.getcurrent() # Update the active list whenever a callback is called def _cb(fileno): if hasattr(g,'idleness'): self.active.add(g) cb(fileno) listener = self.lclass(evtype, fileno, _cb) 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)" % ( evtype, fileno, evtype)) # store off the second listener in another structure self.secondaries[evtype].setdefault(fileno, []).append(listener) else: bucket[fileno] = listener return listener
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
def sleep(seconds=0): """Yield control to another eligible coroutine until at least *seconds* have elapsed. *seconds* may be specified as an integer, or a float if fractional seconds are desired. Calling :func:`~greenthread.sleep` with *seconds* of 0 is the canonical way of expressing a cooperative yield. For example, if one is looping over a large list performing an expensive calculation without calling any socket methods, it's a good idea to call ``sleep(0)`` occasionally; otherwise nothing else will run. """ hub = hubs.get_hub() assert hub.greenlet is not greenlet.getcurrent(), "do not call blocking functions from the mainloop" timer = hub.schedule_call_global(seconds, greenlet.getcurrent().switch) try: hub.switch() finally: timer.cancel()
def sleep(seconds=0): """Yield control to another eligible coroutine until at least *seconds* have elapsed. *seconds* may be specified as an integer, or a float if fractional seconds are desired. Calling :func:`~greenthread.sleep` with *seconds* of 0 is the canonical way of expressing a cooperative yield. For example, if one is looping over a large list performing an expensive calculation without calling any socket methods, it's a good idea to call ``sleep(0)`` occasionally; otherwise nothing else will run. """ hub = hubs.get_hub() assert hub.greenlet is not greenlet.getcurrent( ), 'do not call blocking functions from the mainloop' timer = hub.schedule_call_global(seconds, greenlet.getcurrent().switch) try: hub.switch() finally: timer.cancel()
def g_log(*args): warnings.warn("eventlet.util.g_log is deprecated because " "we're pretty sure no one uses it. " "Send mail to [email protected] " "if you are actually using it.", DeprecationWarning, stacklevel=2) import sys from eventlet.support import greenlets as greenlet g_id = id(greenlet.getcurrent()) if g_id is None: if greenlet.getcurrent().parent is None: ident = 'greenlet-main' else: g_id = id(greenlet.getcurrent()) if g_id < 0: g_id += 1 + ((sys.maxint + 1) << 1) ident = '%08X' % (g_id,) else: ident = 'greenlet-%d' % (g_id,) print >>sys.stderr, '[%s] %s' % (ident, ' '.join(map(str, args)))
def abort(self, wait = False): self.stopping = True gc.collect() aliveGreenlets = self._countManagedGreenlets() if aliveGreenlets <= 0: QCoreApplication.instance().quit() else: logger.warning("Wait for %s greenlets to terminate.", aliveGreenlets) QTimer.singleShot(1000, self._foreToQuitApplication) if wait: assert self.greenlet is not greenlet.getcurrent(), \ "Can't abort with wait from inside the hub's greenlet." self.switch()
def g_log(*args): warnings.warn( "eventlet.util.g_log is deprecated because " "we're pretty sure no one uses it. " "Send mail to [email protected] " "if you are actually using it.", DeprecationWarning, stacklevel=2) import sys from eventlet.support import greenlets as greenlet g_id = id(greenlet.getcurrent()) if g_id is None: if greenlet.getcurrent().parent is None: ident = 'greenlet-main' else: g_id = id(greenlet.getcurrent()) if g_id < 0: g_id += 1 + ((sys.maxint + 1) << 1) ident = '%08X' % (g_id, ) else: ident = 'greenlet-%d' % (g_id, ) print >> sys.stderr, '[%s] %s' % (ident, ' '.join(map(str, args)))
def acquire(self): current = greenlet.getcurrent() if (self._waiters or self._count > 0) and self._holder is not current: # block until lock is free self._waiters.append(current) self._hub.switch() w = self._waiters.popleft() assert w is current, 'Waiting threads woken out of order' assert self._count == 0, 'After waking a thread, the lock must be unacquired' self._holder = current self._count += 1
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 abort(self, wait=False): self.stopping = True gc.collect() aliveGreenlets = self._countManagedGreenlets() if aliveGreenlets <= 0: QCoreApplication.instance().quit() else: logger.warning("Wait for %s greenlets to terminate.", aliveGreenlets) QTimer.singleShot(1000, self._foreToQuitApplication) if wait: assert self.greenlet is not greenlet.getcurrent(), \ "Can't abort with wait from inside the hub's greenlet." self.switch()
def block(self): if self._blocked_thread is not None: raise Exception("Cannot block more than one thread on one BlockedThread") self._blocked_thread = greenlet.getcurrent() try: self._hub.switch() finally: self._blocked_thread = None # cleanup the wakeup task if self._wakeupper is not None: # Important to cancel the wakeup task so it doesn't # spuriously wake this greenthread later on. self._wakeupper.cancel() self._wakeupper = None
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 select(read_list, write_list, error_list, timeout=None): hub = get_hub() t = None current = greenlet.getcurrent() assert hub.greenlet is not current, 'do not call blocking functions from the mainloop' ds = {} for r in read_list: ds[get_fileno(r)] = {'read' : r} for w in write_list: ds.setdefault(get_fileno(w), {})['write'] = w for e in error_list: ds.setdefault(get_fileno(e), {})['error'] = e descriptors = [] def on_read(d): original = ds[get_fileno(d)]['read'] current.switch(([original], [], [])) def on_write(d): original = ds[get_fileno(d)]['write'] current.switch(([], [original], [])) def on_error(d, _err=None): original = ds[get_fileno(d)]['error'] current.switch(([], [], [original])) def on_timeout(): current.switch(([], [], [])) if timeout is not None: t = hub.schedule_call_global(timeout, on_timeout) try: for k, v in ds.iteritems(): d = hub.add_descriptor(k, v.get('read') is not None and on_read, v.get('write') is not None and on_write, v.get('error') is not None and on_error) descriptors.append(d) try: return hub.switch() finally: for d in descriptors: hub.remove_descriptor(d) finally: if t is not None: t.cancel()
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 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 current_thread(): global __patched_enumerate g = greenlet.getcurrent() if not g: # Not currently in a greenthread, fall back to standard function return _fixup_thread(__orig_threading.current_thread()) try: active = __threadlocal.active except AttributeError: active = __threadlocal.active = {} g_id = id(g) t = active.get(g_id) if t is not None: return t # FIXME: move import from function body to top # (jaketesler@github) Furthermore, I was unable to have the current_thread() return correct results from # threading.enumerate() unless the enumerate() function was a) imported at runtime using the gross __import__() call # and b) was hot-patched using patch_function(). # https://github.com/eventlet/eventlet/issues/172#issuecomment-379421165 if __patched_enumerate is None: __patched_enumerate = eventlet.patcher.patch_function( __import__('threading').enumerate) found = [th for th in __patched_enumerate() if th.ident == g_id] if found: return found[0] # Add green thread to active if we can clean it up on exit def cleanup(g): del active[g_id] try: g.link(cleanup) except AttributeError: # Not a GreenThread type, so there's no way to hook into # the green thread exiting. Fall back to the standard # function then. t = _fixup_thread(__orig_threading.current_thread()) else: t = active[g_id] = _GreenThread(g) return t
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 schedule_call_idleness(self, seconds, cb, *args, **kw): """Schedule a callable to be called after 'seconds' seconds have elapsed. Cancel the timer if greenlet has exited. count only idle time - i.e. non active time passing. seconds: The number of idle 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. """ # mark the greenlent to calculate idle time g = greenlet.getcurrent() g.idleness = 1 # may be extended in the future to counting timers t = timer.LocalTimer(seconds, cb, *args, **kw) # mark the timer to consider idle time t.idleness = True # Set the timer to the initial active_clock of the greenlet timer.active_clock = g.active_clock self.add_timer(t) return t
def trampoline(fd, read=None, write=None, timeout=None, timeout_exc=TimeoutError): """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. """ t = None hub = get_hub() current = greenlet.getcurrent() assert hub.greenlet is not current, 'do not call blocking functions from the mainloop' fileno = getattr(fd, 'fileno', lambda: fd)() def _do_close(_d, error=None): if error is None: current.throw(socket.error(32, 'Broken pipe')) else: current.throw(getattr(error, 'value', error)) # XXX convert to socket.error def cb(d): current.switch() # with TwistedHub, descriptor is actually an object (socket_rwdescriptor) which stores # this callback. If this callback stores a reference to the socket instance (fd) # then descriptor has a reference to that instance. This makes socket not collected # after greenlet exit. Since nobody actually uses the results of this switch, I removed # fd from here. If it will be needed than an indirect reference which is discarded right # after the switch above should be used. if timeout is not None: t = hub.schedule_call_global(timeout, current.throw, timeout_exc) try: descriptor = hub.add_descriptor(fileno, read and cb, write and cb, _do_close) try: return hub.switch() finally: hub.remove_descriptor(descriptor) finally: if t is not None: t.cancel()
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()) clear_sys_exc_info() if self.greenlet.dead: self.greenlet = greenlet.greenlet(self.run) try: if self.greenlet.parent is not cur: cur.parent = self.greenlet except ValueError: pass # gets raised if there is a greenlet parent cycle del cur, switch_out clear_sys_exc_info() return self.greenlet.switch()
def wait(self, timeout=None): """Wait until another coroutine calls :meth:`send`. Returns the value the other coroutine passed to :meth:`send`. >>> import eventlet >>> evt = eventlet.Event() >>> def wait_on(): ... retval = evt.wait() ... print("waited for {0}".format(retval)) >>> _ = eventlet.spawn(wait_on) >>> evt.send('result') >>> eventlet.sleep(0) waited for result Returns immediately if the event has already occurred. >>> evt.wait() 'result' When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof). """ current = greenlet.getcurrent() if self._result is NOT_USED: hub = hubs.get_hub() self._waiters.add(current) timer = None if timeout is not None: timer = hub.schedule_call_local(timeout, self._do_send, None, None, current) try: result = hub.switch() if timer is not None: timer.cancel() return result finally: self._waiters.discard(current) if self._exc is not None: current.throw(*self._exc) return self._result
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 get_ident(gr=None): if gr is None: return id(greenlet.getcurrent()) else: return id(gr)
# of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """Integrate eventlet with twisted's reactor mainloop. You generally don't have to use it unless you need to call reactor.run() yourself. """ from eventlet.hubs.twistedr import BaseTwistedHub from eventlet.api import use_hub, _threadlocal from eventlet.support import greenlets as greenlet use_hub(BaseTwistedHub) assert not hasattr(_threadlocal, 'hub') hub = _threadlocal.hub = _threadlocal.Hub(greenlet.getcurrent())
def __init__(self, *args, **kwargs): self.greenlet = greenlet.getcurrent() DelayedCall.__init__(self, *args, **kwargs)
def interrupt_main(): curr = greenlet.getcurrent() if curr.parent and not curr.parent.dead: curr.parent.throw(KeyboardInterrupt()) else: raise KeyboardInterrupt()
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 __init__(self, evtype, fileno, cb): self.where_called = traceback.format_stack() self.greenlet = greenlet.getcurrent() super(DebugListener, self).__init__(evtype, fileno, cb)
def stop(self): self.abort() if self.greenlet is not greenlet.getcurrent(): self.switch()
def __init__(self, *args, **kwargs): self.greenlet = greenlet.getcurrent() Timer.__init__(self, *args, **kwargs)
"""Integrate eventlet with twisted's reactor mainloop. You generally don't have to use it unless you need to call reactor.run() yourself. """ from eventlet.hubs.twistedr import BaseTwistedHub from eventlet.support import greenlets as greenlet from eventlet.hubs import _threadlocal, use_hub use_hub(BaseTwistedHub) assert not hasattr(_threadlocal, 'hub') hub = _threadlocal.hub = _threadlocal.Hub(greenlet.getcurrent())
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)