Source code for guv.hubs.switch

import greenlet

from .hub import get_hub
from ..timeout import Timeout

__all__ = ['gyield', 'trampoline']


[docs]def gyield(switch_back=True): """Yield to other greenlets This is a cooperative yield which suspends the current greenlet and allows other greenlets to run by switching to the hub. - If `switch_back` is True (default), the current greenlet is resumed at the beginning of the next event loop iteration, before the loop polls for I/O and calls any I/O callbacks. This is the intended use for this function the vast majority of the time. - If `switch_back` is False, the hub will will never resume the current greenlet (use with caution). This is mainly useful for situations where other greenlets (not the hub) are responsible for switching back to this greenlet. An example is the Event class, where waiters are switched to when the event is ready. :param bool switch_back: automatically switch back to this greenlet on the next event loop cycle """ current = greenlet.getcurrent() hub = get_hub() if switch_back: hub.schedule_call_now(current.switch) hub.switch()
[docs]def trampoline(fd, evtype, timeout=None, timeout_exc=Timeout): """Jump from the current greenlet to the hub and wait until the given file descriptor is ready for I/O, or the specified timeout elapses If the specified `timeout` elapses before the socket is ready to read or write, `timeout_exc` will be raised instead of :func:`trampoline()` returning normally. When the specified file descriptor is ready for I/O, the hub internally calls the callback to switch back to the current (this) greenlet. Conditions: - must not be called from the hub greenlet (can be called from any other greenlet) - `evtype` must be either :attr:`~guv.const.READ` or :attr:`~guv.const.WRITE` (not possible to watch for both simultaneously) :param int fd: file descriptor :param int evtype: either the constant :attr:`~guv.const.READ` or :attr:`~guv.const.WRITE` :param float timeout: (optional) maximum time to wait in seconds :param Exception timeout_exc: (optional) timeout Exception class """ #: :type: AbstractHub hub = get_hub() current = greenlet.getcurrent() assert hub is not current, 'do not call blocking functions from the mainloop' assert isinstance(fd, int) timer = None if timeout is not None: def _timeout(exc): # timeout has passed current.throw(exc) timer = hub.schedule_call_global(timeout, _timeout, timeout_exc) try: # add a watcher for this file descriptor listener = hub.add(evtype, fd, current.switch, current.throw) # switch to the hub try: return hub.switch() finally: # log.debug('(trampoline finally) remove listener for fd: {}'.format(fd)) hub.remove(listener) finally: if timer is not None: timer.cancel()