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 get(url): hub = evy.hubs.get_hub() c = pycurl_orig.Curl() c.setopt(pycurl_orig.URL, url) c.setopt(pycurl_orig.NOSIGNAL, 1) THE_MULTI.add_handle(c) hub.add_observer(runloop_observer, 'before_waiting') while True: print "TOP" result, numhandles = THE_MULTI.socket_all() print "PERFORM RESULT", result while result == pycurl_orig.E_CALL_MULTI_PERFORM: result, numhandles = THE_MULTI.socket_all() print "PERFORM RESULT2", result if LAST_SOCKET_DONE: break SUSPENDED_COROS[LAST_SOCKET] = greenlet.getcurrent() print "SUSPENDED", SUSPENDED_COROS evy.hubs.get_hub().switch() print "BOTTOM" if not SUSPENDED_COROS: hub.remove_observer(runloop_observer)
def cede(self): """ Switch temporarily to any other greenlet, and then return to the current greenlet :return: the greenlet that takes control """ current = greenlet.getcurrent() self.run_callback(current.switch) return self.switch()
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 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 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 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 abort (self, wait = False): """ Stop the loop. If run is executing, it will exit after completing the next loop 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.run_callback(lambda: None) # switch to it; when done the hub will switch back to its parent, # the main greenlet self.switch()
def abort(self, wait=False): """ Stop the loop. If run is executing, it will exit after completing the next loop 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.run_callback(lambda: None) # switch to it; when done the hub will switch back to its parent, # the main greenlet self.switch()
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: self.timer = None # "fake" timeout (never expires) else: hub = get_hub() if self.exception is None or isinstance(self.exception, bool): # timeout that raises self exc = self else: # regular timeout with user-provided exception exc = self.exception self.timer = hub.schedule_call_global(self.seconds, greenlet.getcurrent().throw, exc) self.timer.forget() ## forget about the timer, so we do not keep the loop alive... return self
def trampoline(fd, read=None, write=None, timeout=None, timeout_exc=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()
def switch (self): """ Switches to a different greenlet :return: :rtype: """ 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 trampoline (fd, read = None, write = None, timeout = None, timeout_exc = 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()
def switch(self): """ Switches to a different greenlet :return: :rtype: """ 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 wait (self, timeout = None, exception = None): """ Wait until another coroutine calls :meth:`send`. Returns the value the other coroutine passed to :meth:`send`. >>> from evy import event >>> import evy >>> evt = event.Event() >>> def wait_on(): ... retval = evt.wait() ... print "waited for", retval >>> _ = evy.spawn(wait_on) >>> evt.send('result') >>> 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: with Timeout(timeout, exception): 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, timeout=None, exception=None): """ Wait until another coroutine calls :meth:`send`. Returns the value the other coroutine passed to :meth:`send`. >>> from evy import event >>> import evy >>> evt = event.Event() >>> def wait_on(): ... retval = evt.wait() ... print "waited for", retval >>> _ = evy.spawn(wait_on) >>> evt.send('result') >>> 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: with Timeout(timeout, exception): 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 get_ident (gr = None): if gr is None: return id(greenlet.getcurrent()) else: return id(gr)
def __init__(self, *args, **kwargs): self.greenlet = greenlet.getcurrent() Timer.__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()