def test_explicit_hub(self): oldhub = api.get_hub() try: api.use_hub(Foo) assert isinstance(api.get_hub(), Foo), api.get_hub() finally: api._threadlocal.hub = oldhub check_hub()
def __call__(self, *args): if not self.called: self.called = True cb, args, kw = self.tpl try: cb(*args, **kw) finally: get_hub().timer_finished(self)
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 try: cb(*args, **kw) finally: get_hub().timer_finished(self)
def cancel(self): """Prevent this timer from being called. If the timer has already been called, has no effect. """ self._cancelled = True self.called = True get_hub().timer_canceled(self) try: del self.tpl except AttributeError: pass
def check_hub(): # Clear through the descriptor queue api.sleep(0) api.sleep(0) hub = api.get_hub() for nm in 'get_readers', 'get_writers', 'get_excs': dct = getattr(hub, nm)() assert not dct, "hub.%s not empty: %s" % (nm, dct) # Stop the runloop (unless it's twistedhub which does not support that) if not getattr(api.get_hub(), 'uses_twisted_reactor', None): api.get_hub().abort() api.sleep(0)
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 accept(sock, handler): try: print 'listening on', sock.getsockname() while True: try: handler(*sock.accept()) except KeyboardInterrupt: api.get_hub().remove_descriptor(sock.fileno()) break finally: try: sock.close() except socket.error: pass
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 _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 send(self, result=None, exc=None): """Makes arrangements for the waiters to be woken with the result and then returns immediately to the parent. >>> from eventlet import coros, api >>> evt = coros.event() >>> def waiter(): ... print 'about to wait' ... result = evt.wait() ... print 'waited for', result >>> _ = api.spawn(waiter) >>> api.sleep(0) about to wait >>> evt.send('a') >>> api.sleep(0) waited for a It is an error to call send() multiple times on the same event. >>> evt.send('whoops') Traceback (most recent call last): ... AssertionError: Trying to re-send() an already-triggered event. Use reset() between send()s to reuse an event object. """ assert self._result is NOT_USED, 'Trying to re-send() an already-triggered event.' self._result = result if exc is not None and not isinstance(exc, tuple): exc = (exc, ) self._exc = exc hub = api.get_hub() if self._waiters: hub.schedule_call_global(0, self._do_send, self._result, self._exc, self._waiters.copy())
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 _write_file(self): outgoing_file = self.outgoing_files.items[0][0] if outgoing_file.size is None or outgoing_file.position < outgoing_file.size: try: piece = outgoing_file.fileobj.read(self.FILE_PIECE_SIZE) except Exception: self.logger.err('error while reading file %r\n%s' % (outgoing_file, traceback.format_exc())) return self.logger.debug('_write_file: read %s bytes from %s' % (len(piece), outgoing_file)) chunk = self.msrp.make_chunk(contflag='X', start=outgoing_file.position+1, end='*', length=outgoing_file.size or '*', message_id=outgoing_file.message_id) chunk.headers.update(outgoing_file.headers) id = chunk.transaction_id assert id not in self.expected_responses, "MSRP transaction %r is already in progress" % id cb_and_timer = [outgoing_file.on_transaction_response, None] self.expected_responses[id] = cb_and_timer try: trailer = chunk.encode_start() self.msrp.write(trailer) self.logger.sent_new_chunk(trailer, self.msrp, chunk=chunk) self.logger.debug('_write_file: wrote header %r' % chunk) try: while piece: self.msrp.write(piece) self.logger.sent_chunk_data(piece, self.msrp, transaction_id=chunk.transaction_id) outgoing_file.position += len(piece) #self.logger.debug('_write_file: wrote %s bytes' % len(piece)) for x in self.outgoing.items: # stop sending the file if there is something else in the queue other than files if x is not GOT_NEW_FILE: return if outgoing_file.size is None or outgoing_file.position < outgoing_file.size: try: piece = outgoing_file.fileobj.read(self.FILE_PIECE_SIZE) except Exception: self.logger.err('error while reading file %r\n%s' % (outgoing_file, traceback.format_exc())) return else: break finally: if not piece or outgoing_file.position == outgoing_file.size: contflag = '$' if self.outgoing_files: self.outgoing_files.wait() else: contflag = '+' footer = chunk.encode_end(contflag) self.msrp.write(footer) self.logger.sent_chunk_end(footer, self.msrp, transaction_id=chunk.transaction_id) self.logger.debug('_write_file: wrote chunk end %s' % contflag) except: self.expected_responses.pop(id, None) raise else: timeout_error = Response408Timeout if chunk.failure_report=='yes' else Response200OK timer = api.get_hub().schedule_call_global(self.RESPONSE_TIMEOUT, self._response_timeout, id, timeout_error) self.last_expected_response = time() + self.RESPONSE_TIMEOUT cb_and_timer[1] = timer
def test_sleep(self): # even if there was an error in the mainloop, the hub should continue to work start = time.time() api.sleep(DELAY) delay = time.time() - start assert delay >= DELAY*0.9, 'sleep returned after %s seconds (was scheduled for %s)' % (delay, DELAY) def fail(): 1/0 api.get_hub().schedule_call_global(0, fail) start = time.time() api.sleep(DELAY) delay = time.time() - start assert delay >= DELAY*0.9, 'sleep returned after %s seconds (was scheduled for %s)' % (delay, DELAY)
def close(self, *args, **kw): if self.closed: return self.closed = True if self.is_secure: # *NOTE: This is not quite the correct SSL shutdown sequence. # We should actually be checking the return value of shutdown. # Note also that this is not the same as calling self.shutdown(). self.fd.shutdown() fn = self.close = self.fd.close try: res = fn(*args, **kw) finally: # This will raise socket.error(32, 'Broken pipe') if there's # a caller waiting on trampoline (e.g. server on .accept()) get_hub().exc_descriptor(self._fileno) return res
def test_schedule(self): hub = api.get_hub() # clean up the runloop, preventing side effects from previous tests # on this thread if hub.running: hub.abort() api.sleep(0) called = [] #t = timer.Timer(0, lambda: (called.append(True), hub.abort())) #t.schedule() # let's have a timer somewhere in the future; make sure abort() still works # (for libevent, its dispatcher() does not exit if there is something scheduled) # XXX libevent handles this, other hubs do not #api.get_hub().schedule_call_global(10000, lambda: (called.append(True), hub.abort())) api.get_hub().schedule_call_global(0, lambda: (called.append(True), hub.abort())) hub.default_sleep = lambda: 0.0 hub.switch() assert called assert not hub.running
def testInterruptedTimeout(self): # XXX I don't know how to do this test on MSWindows or any other # plaform that doesn't support signal.alarm() or os.kill(), though # the bug should have existed on all platforms. if not hasattr(signal, "alarm"): return # can only test on *nix self.serv.settimeout(5.0) # must be longer than alarm class Alarm(Exception): pass def alarm_handler(signal, frame): raise Alarm from eventlet.api import get_hub if hasattr(get_hub(), 'signal'): myalarm = get_hub().signal(signal.SIGALRM, alarm_handler) else: old_alarm = signal.signal(signal.SIGALRM, alarm_handler) try: try: signal.alarm( 2) # POSIX allows alarm to be up to 1 second early try: foo = self.serv.accept() except socket.timeout: self.fail("caught timeout instead of Alarm") except Alarm: pass except: self.fail("caught other exception instead of Alarm") else: self.fail("nothing caught") signal.alarm(0) # shut off alarm except Alarm: self.fail("got Alarm in wrong place") finally: # no alarm can be pending. Safe to restore old handler. if hasattr(get_hub(), 'signal'): myalarm.cancel() else: signal.signal(signal.SIGALRM, old_alarm)
def test_sleep(self): # even if there was an error in the mainloop, the hub should continue to work start = time.time() api.sleep(DELAY) delay = time.time() - start assert delay >= DELAY * 0.9, 'sleep returned after %s seconds (was scheduled for %s)' % ( delay, DELAY) def fail(): 1 / 0 api.get_hub().schedule_call_global(0, fail) start = time.time() api.sleep(DELAY) delay = time.time() - start assert delay >= DELAY * 0.9, 'sleep returned after %s seconds (was scheduled for %s)' % ( delay, DELAY)
def server(sock, site, log=None, max_size=512, serv=None, max_http_version=DEFAULT_MAX_HTTP_VERSION): pool = Pool(max_size=max_size) if serv is None: serv = Server(sock, sock.getsockname(), site, log, max_http_version=max_http_version) try: serv.log.write("httpd starting up on %s\n" % (sock.getsockname(), )) while True: try: new_sock, address = sock.accept() proto = HttpProtocol(new_sock, address, serv) pool.execute_async(proto.handle) api.sleep(0) # sleep to allow other coros to run except KeyboardInterrupt: api.get_hub().remove_descriptor(sock.fileno()) serv.log.write("httpd exiting\n") break finally: try: sock.close() except socket.error: pass
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 serve(self, interface='0.0.0.0', port=3000): self.log.info('ZenQueue Native Server v%s', zenqueue.__version__) if interface == '0.0.0.0': self.log.info('Serving on %s:%d (all interfaces)', interface, port) else: self.log.info('Serving on %s:%d', interface, port) self.socket = api.tcp_listener((interface, port)) # A lot of the code below was copied or adapted from eventlet's # implementation of an asynchronous WSGI server. try: while True: try: try: client_socket, client_addr = self.socket.accept() except socket.error, exc: # EPIPE (Broken Pipe) and EBADF (Bad File Descriptor) # errors are common for clients that suddenly quit. We # shouldn't worry so much about them. if exc[0] not in [errno.EPIPE, errno.EBADF]: raise # Throughout the logging output, we use the client's ID in # hexadecimal to identify a particular client in the logs. self.log.info('Client %x connected: %r', id(client_socket), client_addr) # Handle this client on the pool, sleeping for 0 time to # allow the handler (or other coroutines) to run. self.client_pool.execute_async(self.handle, client_socket) api.sleep(0) except KeyboardInterrupt: # It's a fatal error because it kills the program. self.log.fatal('Received keyboard interrupt.') # This removes the socket from the current hub's list of # sockets to check for clients (i.e. the select() call). # select() is a key component of asynchronous networking. api.get_hub().remove_descriptor(self.socket.fileno()) break
def testInterruptedTimeout(self): # XXX I don't know how to do this test on MSWindows or any other # plaform that doesn't support signal.alarm() or os.kill(), though # the bug should have existed on all platforms. if not hasattr(signal, "alarm"): return # can only test on *nix self.serv.settimeout(5.0) # must be longer than alarm class Alarm(Exception): pass def alarm_handler(signal, frame): raise Alarm from eventlet.api import get_hub if hasattr(get_hub(), 'signal'): myalarm = get_hub().signal(signal.SIGALRM, alarm_handler) else: old_alarm = signal.signal(signal.SIGALRM, alarm_handler) try: try: signal.alarm(2) # POSIX allows alarm to be up to 1 second early try: foo = self.serv.accept() except socket.timeout: self.fail("caught timeout instead of Alarm") except Alarm: pass except: self.fail("caught other exception instead of Alarm") else: self.fail("nothing caught") signal.alarm(0) # shut off alarm except Alarm: self.fail("got Alarm in wrong place") finally: # no alarm can be pending. Safe to restore old handler. if hasattr(get_hub(), 'signal'): myalarm.cancel() else: signal.signal(signal.SIGALRM, old_alarm)
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 backdoor_server(server, locals=None): print "backdoor listening on %s:%s" % server.getsockname() try: try: while True: (conn, (host, port)) = server.accept() print "backdoor connected to %s:%s" % (host, port) fl = conn.makeGreenFile("rw") fl.newlines = '\n' greenlet = SocketConsole(fl, (host, port), locals) hub = api.get_hub() hub.schedule_call_global(0, greenlet.switch) except socket.error, e: # Broken pipe means it was shutdown if e[0] != 32: raise finally: server.close()
def _write_chunk(self, chunk, response_cb=None): id = chunk.transaction_id assert id not in self.expected_responses, "MSRP transaction %r is already in progress" % id if response_cb is not None: # since reader is in another greenlet and write() will switch the greenlets, # let's setup response_cb and timer before write() call, just in case cb_and_timer = [response_cb, None] self.expected_responses[id] = cb_and_timer try: self.msrp.write_chunk(chunk) except: if response_cb is not None: self.expected_responses.pop(id, None) raise else: if response_cb is not None: timeout_error = Response408Timeout if chunk.failure_report=='yes' else Response200OK timer = api.get_hub().schedule_call_global(self.RESPONSE_TIMEOUT, self._response_timeout, id, timeout_error) self.last_expected_response = time() + self.RESPONSE_TIMEOUT cb_and_timer[1] = timer
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 exit_unless_twisted(): from eventlet.api import get_hub if 'Twisted' not in type(get_hub()).__name__: exit_disabled()
def test_global(self): lst = [1] api.spawn(api.get_hub().schedule_call_global, DELAY, lst.pop) api.sleep(DELAY * 2) assert lst == [], lst
def some_work(): api.get_hub().schedule_call_local(0, fire_timer)
def stop(self): from twisted.internet import reactor reactor.callLater(0, reactor.stop) from eventlet.api import get_hub get_hub().switch()
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
sys.exit('No hub %s: %s' % (hub, ex)) else: r.install() use_hub('twistedr') def parse_args(): hub = None reactor = None del sys.argv[0] # kill with_eventlet.py if sys.argv[0]=='--hub': del sys.argv[0] hub = sys.argv[0] del sys.argv[0] if sys.argv[0]=='--reactor': del sys.argv[0] reactor = sys.argv[0] del sys.argv[0] return hub, reactor if __name__=='__main__': hub, reactor = parse_args() setup_hub(hub, reactor) from eventlet.api import get_hub hub = get_hub() # set up the hub now print '===HUB=%r' % hub if 'twisted.internet.reactor' in sys.modules: print '===REACTOR=%r' % sys.modules['twisted.internet.reactor'] sys.stdout.flush() execfile(sys.argv[0])
def gethostbyname(name): if getattr(get_hub(), 'uses_twisted_reactor', None): globals()['gethostbyname'] = _gethostbyname_twisted else: globals()['gethostbyname'] = _gethostbyname_tpool return globals()['gethostbyname'](name)
hub.schedule_call_global(0, greenlet.switch) except socket.error, e: # Broken pipe means it was shutdown if e[0] != 32: raise finally: server.close() def backdoor((conn, addr), locals=None): """ Use this with tcp_server like so: api.tcp_server( api.tcp_listener(('127.0.0.1', 9000)), backdoor.backdoor, {}) """ host, port = addr print "backdoor to %s:%s" % (host, port) fl = conn.makeGreenFile("rw") fl.newlines = '\n' greenlet = SocketConsole(fl, (host, port), locals) hub = api.get_hub() hub.schedule_call_global(0, greenlet.switch) if __name__ == '__main__': api.tcp_server(api.tcp_listener(('127.0.0.1', 9000)), backdoor, {})
class TestApi(TestCase): mode = 'static' certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt') private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key') def test_tcp_listener(self): socket = api.tcp_listener(('0.0.0.0', 0)) assert socket.getsockname()[0] == '0.0.0.0' socket.close() check_hub() def test_connect_tcp(self): def accept_once(listenfd): try: conn, addr = listenfd.accept() fd = conn.makeGreenFile() conn.close() fd.write('hello\n') fd.close() finally: listenfd.close() server = api.tcp_listener(('0.0.0.0', 0)) api.spawn(accept_once, server) client = api.connect_tcp(('127.0.0.1', server.getsockname()[1])) fd = client.makeGreenFile() client.close() assert fd.readline() == 'hello\n' assert fd.read() == '' fd.close() check_hub() def test_connect_ssl(self): def accept_once(listenfd): try: conn, addr = listenfd.accept() fl = conn.makeGreenFile('w') fl.write('hello\r\n') fl.close() conn.close() finally: listenfd.close() server = api.ssl_listener(('0.0.0.0', 0), self.certificate_file, self.private_key_file) api.spawn(accept_once, server) client = util.wrap_ssl( api.connect_tcp(('127.0.0.1', server.getsockname()[1]))) client = client.makeGreenFile() assert client.readline() == 'hello\r\n' assert client.read() == '' client.close() def test_server(self): connected = [] server = api.tcp_listener(('0.0.0.0', 0)) bound_port = server.getsockname()[1] def accept_twice((conn, addr)): connected.append(True) conn.close() if len(connected) == 2: server.close() api.call_after(0, api.connect_tcp, ('127.0.0.1', bound_port)) api.call_after(0, api.connect_tcp, ('127.0.0.1', bound_port)) try: api.tcp_server(server, accept_twice) except: api.sleep(0.1) raise assert len(connected) == 2 check_hub() def test_001_trampoline_timeout(self): server = api.tcp_listener(('0.0.0.0', 0)) bound_port = server.getsockname()[1] try: desc = greenio.GreenSocket(util.tcp_socket()) desc.connect(('127.0.0.1', bound_port)) api.trampoline(desc, read=True, write=False, timeout=0.1) except api.TimeoutError: pass # test passed else: assert False, "Didn't timeout" check_hub() def test_timeout_cancel(self): server = api.tcp_listener(('0.0.0.0', 0)) bound_port = server.getsockname()[1] def client_connected((conn, addr)): conn.close() def go(): client = util.tcp_socket() desc = greenio.GreenSocket(client) desc.connect(('127.0.0.1', bound_port)) try: api.trampoline(desc, read=True, write=True, timeout=0.1) except api.TimeoutError: assert False, "Timed out" server.close() client.close() api.call_after(0, go) api.tcp_server(server, client_connected) check_hub() if not getattr(api.get_hub(), 'uses_twisted_reactor', None): def test_explicit_hub(self): oldhub = api.get_hub() try: api.use_hub(Foo) assert isinstance(api.get_hub(), Foo), api.get_hub() finally: api._threadlocal.hub = oldhub check_hub() def test_named(self): named_foo = api.named('api_test.Foo') self.assertEquals(named_foo.__name__, "Foo") def test_naming_missing_class(self): self.assertRaises(ImportError, api.named, 'this_name_should_hopefully_not_exist.Foo') def test_timeout_and_final_write(self): # This test verifies that a write on a socket that we've # stopped listening for doesn't result in an incorrect switch rpipe, wpipe = os.pipe() rfile = os.fdopen(rpipe, "r", 0) wrap_rfile = greenio.GreenPipe(rfile) wfile = os.fdopen(wpipe, "w", 0) wrap_wfile = greenio.GreenPipe(wfile) def sender(evt): api.sleep(0.02) wrap_wfile.write('hi') evt.send('sent via event') from eventlet import coros evt = coros.event() api.spawn(sender, evt) try: # try and get some data off of this pipe # but bail before any is sent api.exc_after(0.01, api.TimeoutError) _c = wrap_rfile.read(1) self.fail() except api.TimeoutError: pass result = evt.wait() self.assertEquals(result, 'sent via event')
def test_global(self): lst = [1] api.spawn(api.get_hub().schedule_call_global, DELAY, lst.pop) api.sleep(DELAY*2) assert lst == [], lst
def send(self, result=None, exc=None): if exc is not None and not isinstance(exc, tuple): exc = (exc, ) self.items.append((result, exc)) if self._waiters: api.get_hub().schedule_call_global(0, self._do_send)