def wait(self): """Wait until another coroutine calls send. Returns the value the other coroutine passed to send. >>> from eventlet import coros, api >>> evt = coros.event() >>> def wait_on(): ... retval = evt.wait() ... print "waited for", retval >>> _ = api.spawn(wait_on) >>> evt.send('result') >>> api.sleep(0) waited for result Returns immediately if the event has already occured. >>> evt.wait() 'result' """ if self._result is NOT_USED: self._waiters.add(api.getcurrent()) try: return api.get_hub().switch() finally: self._waiters.discard(api.getcurrent()) if self._exc is not None: api.getcurrent().throw(*self._exc) return self._result
def switch(self): assert api.getcurrent() is not self.greenlet, "Cannot switch from MAINLOOP to MAINLOOP" try: api.getcurrent().parent = self.greenlet except ValueError: pass return self.greenlet.switch()
def wait(self): """The difference from Queue.wait: if there is an only item in the Queue and it is an exception, raise it, but keep it in the Queue, so that future calls to wait() will raise it again. """ if self.has_error() and len(self.items)==1: # the last item, which is an exception, raise without emptying the Queue getcurrent().throw(*self.items[0][1]) else: return Queue.wait(self)
def acquire(self, blocking=True): if not blocking and self.locked(): return False if self.counter <= 0: self._waiters.add(api.getcurrent()) try: while self.counter <= 0: api.get_hub().switch() finally: self._waiters.discard(api.getcurrent()) self.counter -= 1 return True
def link_exception(self, listener=None, link=None): if self.value is not _NOT_USED and self._exc is None: return if listener is None: listener = api.getcurrent() if link is None: link = self.getLink(listener) if self.ready() and listener is api.getcurrent(): link(self) else: self._exception_links[listener] = link if self.value is not _NOT_USED: self._start_send_exception() return link
def block_on(deferred): cur = [getcurrent()] synchronous = [] def cb(value): if cur: if getcurrent() is cur[0]: synchronous.append((value, None)) else: cur[0].switch(value) return value def eb(failure): if cur: if getcurrent() is cur[0]: synchronous.append((None, failure)) else: failure.throwExceptionIntoGenerator(cur[0]) deferred.addCallbacks(cb, eb) if synchronous: result, failure = synchronous[0] if failure is not None: failure.raiseException() return result try: return get_hub().switch() finally: del cur[0]
def switch(self): cur = api.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: traceback.print_exception(*sys.exc_info()) if self.greenlet.dead: self.greenlet = api.Greenlet(self.run) try: api.getcurrent().parent = self.greenlet except ValueError: pass return self.greenlet.switch()
def send(self, value): """Wake up the greenlet that is calling wait() currently (if there is one). Can only be called from get_hub().greenlet. """ assert api.getcurrent() is hubs.get_hub().greenlet if self.greenlet is not None: self.greenlet.switch(value)
def send_exception(self, *throw_args): """Make greenlet calling wait() wake up (if there is a wait()). Can only be called from get_hub().greenlet. """ assert api.getcurrent() is hubs.get_hub().greenlet if self.greenlet is not None: self.greenlet.throw(*throw_args)
def cb(value): if cur: if getcurrent() is cur[0]: synchronous.append((value, None)) else: cur[0].switch(value) return value
def execute(self, func, *args, **kwargs): """Execute func in one of the coroutines maintained by the pool, when one is free. Immediately returns a Proc object which can be queried for the func's result. >>> pool = Pool() >>> task = pool.execute(lambda a: ('foo', a), 1) >>> task.wait() ('foo', 1) """ # if reentering an empty pool, don't try to wait on a coroutine freeing # itself -- instead, just execute in the current coroutine if self.sem.locked() and api.getcurrent() in self.procs: p = proc.spawn(func, *args, **kwargs) try: p.wait() except: pass else: self.sem.acquire() p = self.procs.spawn(func, *args, **kwargs) # assuming the above line cannot raise p.link(lambda p: self.sem.release()) if self.results is not None: p.link(self.results) return p
def execute(self, func, *args, **kwargs): """Execute func in one of the coroutines maintained by the pool, when one is free. Immediately returns a :class:`~eventlet.proc.Proc` object which can be queried for the func's result. >>> pool = Pool() >>> task = pool.execute(lambda a: ('foo', a), 1) >>> task.wait() ('foo', 1) """ # if reentering an empty pool, don't try to wait on a coroutine freeing # itself -- instead, just execute in the current coroutine if self.sem.locked() and api.getcurrent() in self.procs: p = proc.spawn(func, *args, **kwargs) try: p.wait() except: pass else: self.sem.acquire() p = self.procs.spawn(func, *args, **kwargs) # assuming the above line cannot raise p.link(lambda p: self.sem.release()) if self.results is not None: p.link(self.results) return p
def schedule_call_local(self, seconds, cb, *args, **kwargs): current = api.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 wait(self, timeout=None, *throw_args): """Wait until :meth:`send` or :meth:`send_exception` is called or *timeout* has expired. Return the argument of :meth:`send` or raise the argument of :meth:`send_exception`. If *timeout* has expired, ``None`` is returned. The arguments, when provided, specify how many seconds to wait and what to do when *timeout* has expired. They are treated the same way as :func:`~eventlet.api.timeout` treats them. """ if self.value is not _NOT_USED: if self._exc is None: return self.value else: api.getcurrent().throw(*self._exc) if timeout is not None: timer = api.timeout(timeout, *throw_args) timer.__enter__() if timeout == 0: if timer.__exit__(None, None, None): return else: try: api.getcurrent().throw(*timer.throw_args) except: if not timer.__exit__(*sys.exc_info()): raise return EXC = True try: try: waiter = Waiter() self.link(waiter) try: return waiter.wait() finally: self.unlink(waiter) except: EXC = False if timeout is None or not timer.__exit__(*sys.exc_info()): raise finally: if timeout is not None and EXC: timer.__exit__(None, None, None)
def wait(self, timeout=None, *throw_args): """Wait until :meth:`send` or :meth:`send_exception` is called or *timeout* has expired. Return the argument of :meth:`send` or raise the argument of :meth:`send_exception`. If *timeout* has expired, ``None`` is returned. The arguments, when provided, specify how many seconds to wait and what to do when *timeout* has expired. They are treated the same way as :func:`~eventlet.api.timeout` treats them. """ if self.value is not _NOT_USED: if self._exc is None: return self.value else: api.getcurrent().throw(*self._exc) if timeout is not None: timer = api.timeout(timeout, *throw_args) timer.__enter__() if timeout==0: if timer.__exit__(None, None, None): return else: try: api.getcurrent().throw(*timer.throw_args) except: if not timer.__exit__(*sys.exc_info()): raise return EXC = True try: try: waiter = Waiter() self.link(waiter) try: return waiter.wait() finally: self.unlink(waiter) except: EXC = False if timeout is None or not timer.__exit__(*sys.exc_info()): raise finally: if timeout is not None and EXC: timer.__exit__(None, None, None)
def killall(procs, *throw_args, **kwargs): if not throw_args: throw_args = (ProcExit, ) wait = kwargs.pop('wait', False) if kwargs: raise TypeError('Invalid keyword argument for proc.killall(): %s' % ', '.join(kwargs.keys())) for g in procs: if not g.dead: hubs.get_hub().schedule_call_global(0, g.throw, *throw_args) if wait and api.getcurrent() is not hubs.get_hub().greenlet: api.sleep(0)
def wait(self): """Wait until send or send_exception is called. Return value passed into send() or raise exception passed into send_exception(). """ assert self.greenlet is None current = api.getcurrent() assert current is not hubs.get_hub().greenlet self.greenlet = current try: return hubs.get_hub().switch() finally: self.greenlet = None
def send(self, result=None, exc=None): if exc is not None and not isinstance(exc, tuple): exc = (exc, ) if api.getcurrent() is api.get_hub().greenlet: self.items.append((result, exc)) if self._waiters: api.get_hub().schedule_call_global(0, self._do_switch) else: if self._waiters and self._senders: api.sleep(0) self.items.append((result, exc)) # note that send() does not work well with timeouts. if your timeout fires # after this point, the item will remain in the queue if self._waiters: api.get_hub().schedule_call_global(0, self._do_switch) if len(self.items) > self.max_size: self._senders.add(api.getcurrent()) try: api.get_hub().switch() finally: self._senders.discard(api.getcurrent())
def kill(self, *throw_args): """ Raise an exception in the greenlet. Unschedule the current greenlet so that this :class:`Proc` can handle the exception (or die). The exception can be specified with *throw_args*. By default, :class:`ProcExit` is raised. """ if not self.dead: if not throw_args: throw_args = (ProcExit, ) hubs.get_hub().schedule_call_global(0, self.greenlet.throw, *throw_args) if api.getcurrent() is not hubs.get_hub().greenlet: api.sleep(0)
def run(self): while True: try: self.dispatch() except api.GreenletExit: break except self.SYSTEM_EXCEPTIONS: raise except: if self.signal_exc_info is not None: self.schedule_call_global(0, api.getcurrent().parent.throw, *self.signal_exc_info) self.signal_exc_info = None else: traceback.print_exc()
def start(self): notification_center = NotificationCenter() if self.greenlet is not None: return self.greenlet = api.getcurrent() current_address = host.default_ip while True: new_address = host.default_ip # make sure the address stabilized api.sleep(5) if new_address != host.default_ip: continue if new_address != current_address: notification_center.post_notification(name='SystemIPAddressDidChange', sender=self, data=TimestampedNotificationData(old_ip_address=current_address, new_ip_address=new_address)) current_address = new_address api.sleep(5)
def main(): parser = optparse.OptionParser() parser.add_option("-r", "--reload", action='store_true', dest='reload', help='If --reload is passed, reload the server any time ' 'a loaded module changes.') options, args = parser.parse_args() if len(args) != 5: print "Usage: %s controller_pid httpd_fd death_fd factory_qual factory_args" % ( sys.argv[0], ) sys.exit(1) controller_pid, httpd_fd, death_fd, factory_qual, factory_args = args controller_pid = int(controller_pid) config = api.named(factory_qual)(json.loads(factory_args)) setproctitle("spawn: child (%s)" % ", ".join(config.get("args"))) ## Set up the reloader if options.reload: watch = config.get('watch', None) if watch: watching = ' and %s' % watch else: watching = '' print "(%s) reloader watching sys.modules%s" % (os.getpid(), watching) api.spawn( reloader_dev.watch_forever, controller_pid, 1, watch) ## The parent will catch sigint and tell us to shut down signal.signal(signal.SIGINT, signal.SIG_IGN) api.spawn(read_pipe_and_die, int(death_fd), api.getcurrent()) ## Make the socket object from the fd given to us by the controller sock = greenio.GreenSocket( socket.fromfd(int(httpd_fd), socket.AF_INET, socket.SOCK_STREAM)) serve_from_child( sock, config, controller_pid)
def wait(self): if self.items: result, exc = self.items.popleft() if exc is None: return result else: api.getcurrent().throw(*exc) else: self._waiters.add(api.getcurrent()) try: result, exc = api.get_hub().switch() if exc is None: return result else: api.getcurrent().throw(*exc) finally: self._waiters.discard(api.getcurrent())
def start(self): notification_center = NotificationCenter() if self.greenlet is not None: return self.greenlet = api.getcurrent() current_address = host.default_ip while True: new_address = host.default_ip # make sure the address stabilized api.sleep(5) if new_address != host.default_ip: continue if new_address != current_address: notification_center.post_notification( name='SystemIPAddressDidChange', sender=self, data=TimestampedNotificationData( old_ip_address=current_address, new_ip_address=new_address)) current_address = new_address api.sleep(5)
def wait(self): if self.items: result, exc = self.items.popleft() if len(self.items) <= self.max_size: api.get_hub().schedule_call_global(0, self._do_switch) if exc is None: return result else: api.getcurrent().throw(*exc) else: if self._senders: api.get_hub().schedule_call_global(0, self._do_switch) self._waiters.add(api.getcurrent()) try: result, exc = api.get_hub().switch() if exc is None: return result else: api.getcurrent().throw(*exc) finally: self._waiters.discard(api.getcurrent())
def get_ident(): return id(api.getcurrent())
def __init__(self, *args, **kwargs): self.greenlet = getcurrent() Timer.__init__(self, *args, **kwargs)
def unlink(self, listener=None): if listener is None: listener = api.getcurrent() self._value_links.pop(listener, None) self._exception_links.pop(listener, None)
def main(): if not sys.argv[1:] or sys.argv[1] not in ["client", "server"] or sys.argv[3:]: sys.exit(__doc__) role = sys.argv[1] if sys.argv[2:]: filename = sys.argv[2] else: filename = None if role == "client": local_uri = URI(session_id="client", use_tls=False) remote_uri = URI(session_id="server", use_tls=False) connector = ConnectorDirect(logger=Logger(is_enabled_func=lambda: False)) dest = None else: local_uri = URI(session_id="server", use_tls=False) remote_uri = URI(session_id="client", use_tls=False) connector = AcceptorDirect(logger=Logger(is_enabled_func=lambda: False)) if filename: if os.path.exists(filename) and os.path.isfile(filename): sys.exit("%s already exists. Remove it first or provide another destination" % filename) dest = file(filename, "w+") connector.prepare(local_uri) transport = connector.complete([remote_uri]) main_greenlet = api.getcurrent() def on_received(chunk=None, error=None): if chunk is not None: if chunk.content_type == "text/plain": print "\nreceived message: %s" % chunk.data elif chunk.content_type == "application/octet-stream": fro, to, total = chunk.byte_range dest.seek(fro - 1) dest.write(chunk.data) if total: percent = " (%d%%)" % (100.0 * (fro - 1 + len(chunk.data)) / total) else: percent = "" speed = (fro - 1 + len(chunk.data)) / float((time() - start_time)) / 1024.0 / 1024 print "\rwrote %s bytes to %s. %s bytes total%s %.2f MB/s " % ( len(chunk.data), filename, fro - 1 + len(chunk.data), percent, speed, ), if chunk.contflag == "$": api.spawn(api.kill, main_greenlet, proc.ProcExit) if error is not None: api.spawn(api.kill, main_greenlet, error.type, error.value, error.tb) session = MSRPSession(transport, on_incoming_cb=on_received) def sender(): while True: session.send_message("hello from %s" % role, "text/plain") api.sleep(3) sender = proc.spawn_link_exception(proc.wrap_errors(proc.ProcExit, sender)) if filename and role == "client": if os.path.isfile(filename): size = os.stat(filename).st_size else: size = None f = file(filename) outgoing_file = OutgoingFile(f, size, "application/octet-stream") print "Sending %s %s bytes" % (filename, size) session.send_file(outgoing_file) start_time = time() try: api.get_hub().switch() # sleep forever except (proc.ProcExit, ConnectionDone): pass finally: sender.kill() session.shutdown()
def eb(failure): if cur: if getcurrent() is cur[0]: synchronous.append((None, failure)) else: failure.throwExceptionIntoGenerator(cur[0])
def __init__(self, *args, **kwargs): self.greenlet = api.getcurrent() DelayedCall.__init__(self, *args, **kwargs)