def handle(self, conn, address): f = getcurrent()._fileobj = _fileobject(conn) f.stderr = self.stderr getcurrent().switch_in() try: console = InteractiveConsole(self.locals) # __builtins__ may either be the __builtin__ module or # __builtin__.__dict__ in the latter case typing # locals() at the backdoor prompt spews out lots of # useless stuff try: import __builtin__ console.locals["__builtins__"] = __builtin__ except ImportError: import builtins console.locals["builtins"] = builtins console.interact(banner=self.banner) except SystemExit: # raised by quit() if not PY3: sys.exc_clear() finally: conn.close() f.close() if PYPY: # The underlying socket somewhere has a reference # that's not getting closed until finalizers run. # Without running them, test__backdoor.Test.test_sys_exit # hangs forever gc.collect()
def _notify_links(self): # Subclasses CANNOT override. This is a cdef method. # We release self._notifier here. We are called by it # at the end of the loop, and it is now false in a boolean way (as soon # as this method returns). # If we get acquired/released again, we will create a new one, but there's # no need to keep it around until that point (making it potentially climb # into older GC generations, notably on PyPy) notifier = self._notifier try: while True: self._dirty = False if not self._links: # In case we were manually unlinked before # the callback. Which shouldn't happen return for link in self._links: if self.counter <= 0: return try: link(self) # Must use Cython >= 0.23.4 on PyPy else this leaks memory except: getcurrent().handle_error((link, self), *sys.exc_info()) if self._dirty: # We mutated self._links so we need to start over break if not self._dirty: return finally: # We should not have created a new notifier even if callbacks # released us because we loop through *all* of our links on the # same callback while self._notifier is still true. assert self._notifier is notifier self._notifier = None
def handle(self, conn, _address): # pylint: disable=method-hidden """ Interact with one remote user. .. versionchanged:: 1.1b2 Each connection gets its own ``locals`` dictionary. Previously they were shared in a potentially unsafe manner. """ fobj = conn.makefile(mode="rw") fobj = _fileobject(conn, fobj, self.stderr) getcurrent()._fileobj = fobj getcurrent().switch_in() try: console = InteractiveConsole(self._create_interactive_locals()) if sys.version_info[:3] >= (3, 6, 0): # Beginning in 3.6, the console likes to print "now exiting <class>" # but probably our socket is already closed, so this just causes problems. console.interact(banner=self.banner, exitmsg='') # pylint:disable=unexpected-keyword-arg else: console.interact(banner=self.banner) except SystemExit: # raised by quit() if hasattr(sys, 'exc_clear'): # py2 sys.exc_clear() finally: conn.close() fobj.close()
def test_subscribe(): e = Observer() print '000',getcurrent() getcurrent().in_another_greenlet = in_another_greenlet b = e.subscribe('kill',getcurrent().in_another_greenlet) gevent.sleep(5) print 'END' b.unsubscribe()
def run_subscribe(self): e = Observer() getcurrent().in_another_greenlet = self.in_another_greenlet getcurrent().in_another_greenlet2 = self.in_another_greenlet2 b = e.subscribe('kill',getcurrent().in_another_greenlet) c = e.subscribe('kill',getcurrent().in_another_greenlet2) gevent.sleep(1) b.unsubscribe() c.unsubscribe()
def start(self): """Schedule the timeout.""" 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 = core.timer(self.seconds, getcurrent().throw, self) else: # regular timeout with user-provided exception self.timer = core.timer(self.seconds, getcurrent().throw, self.exception)
def start(self): """Schedule the timeout.""" assert not self.pending, "%r is already started; to restart it, cancel it first" % self if self.seconds is None: # "fake" timeout (never expires) pass elif self.exception is None or self.exception is False or isinstance(self.exception, string_types): # timeout that raises self self.timer.start(getcurrent().throw, self) else: # regular timeout with user-provided exception self.timer.start(getcurrent().throw, self.exception)
def acquire(self, blocking=True): if not blocking and self.locked(): return False if self.counter <= 0: self._waiters.add(getcurrent()) try: while self.counter <= 0: get_hub().switch() finally: self._waiters.discard(getcurrent()) self.counter -= 1 return True
def _notify_links(self): while True: self._dirty = False for link in self._links: if self.counter <= 0: return try: link(self) except: getcurrent().handle_error((link, self), *sys.exc_info()) if self._dirty: break if not self._dirty: return
def __init__(self): # pylint:disable=super-init-not-called #_DummyThread_.__init__(self) # It'd be nice to use a pattern like "greenlet-%d", but maybe somebody out # there is checking thread names... self._name = self._Thread__name = __threading__._newname("DummyThread-%d") # All dummy threads in the same native thread share the same ident # (that of the native thread) self._set_ident() g = getcurrent() gid = _get_ident(g) __threading__._active[gid] = self rawlink = getattr(g, 'rawlink', None) if rawlink is not None: # raw greenlet.greenlet greenlets don't # have rawlink... rawlink(_cleanup) else: # ... so for them we use weakrefs. # See https://github.com/gevent/gevent/issues/918 global _weakref if _weakref is None: _weakref = __import__('weakref') ref = _weakref.ref(g, _make_cleanup_id(gid)) self.__raw_ref = ref
def join(self, timeout=None): """Wait until the greenlet finishes or *timeout* expires. Return ``None`` regardless. """ if self.ready(): return else: switch = getcurrent().switch self.rawlink(switch) try: t = Timeout.start_new(timeout) try: result = self.parent.switch() assert result is self, 'Invalid switch into Greenlet.join(): %r' % (result, ) finally: t.cancel() except Timeout as ex: self.unlink(switch) if ex is not t: raise if PY3: ex.__traceback__ = None except: self.unlink(switch) raise
def link(self, receiver=None, GreenletLink=GreenletLink, SpawnedLink=SpawnedLink): """Link greenlet's completion to callable or another greenlet. If *receiver* is a callable then it will be called with this instance as an argument once this greenlet's dead. A callable is called in its own greenlet. If *receiver* is a greenlet then an :class:`LinkedExited` exception will be raised in it once this greenlet's dead. If *receiver* is ``None``, link to the current greenlet. Always asynchronous, unless receiver is a current greenlet and the result is ready. If this greenlet is already dead, then notification will performed in this loop iteration as soon as this greenlet switches to the hub. """ current = getcurrent() if receiver is None or receiver is current: receiver = GreenletLink(current) if self.ready(): # special case : linking to current greenlet when the result is ready # raise LinkedExited immediatelly receiver(self) return elif not callable(receiver): if isinstance(receiver, greenlet): receiver = GreenletLink(receiver) else: raise TypeError('Expected callable or greenlet: %r' % (receiver, )) else: receiver = SpawnedLink(receiver) self.rawlink(receiver)
def wait_readwrite(fileno, timeout=-1, timeout_exc=_socket.timeout('timed out')): evt = core.readwrite_event(fileno, _wait_helper, timeout, (getcurrent(), timeout_exc)) try: switch_result = get_hub().switch() assert evt is switch_result, 'Invalid switch into wait_readwrite(): %r' % (switch_result, ) finally: evt.cancel()
def wait(self, timeout=None): """Block until the instance is ready. If this instance already holds a value / an exception, return immediatelly. Otherwise, block until another thread calls :meth:`set` or :meth:`set_exception` or until the optional timeout occurs. 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). This method always returns ``None`` regardless of the reason it returns. To find out out what happened, use :meth:`ready` and :meth:`successful` methods or :attr:`value` and :attr:`exception` properties. """ if self._exception is not _NONE: return else: switch = getcurrent().switch self.rawlink(switch) try: timer = Timeout.start_new(timeout) try: result = get_hub().switch() assert result is self, 'Invalid switch into AsyncResult.wait(): %r' % (result, ) finally: timer.cancel() except Timeout, exc: self.unlink(switch) if exc is not timer: raise except:
def _do_wait(self, timeout): """ Wait for up to *timeout* seconds to expire. If timeout elapses, return the exception. Otherwise, return None. Raises timeout if a different timer expires. """ switch = getcurrent().switch self.rawlink(switch) try: # As a tiny efficiency optimization, avoid allocating a timer # if not needed. timer = Timeout.start_new(timeout) if timeout is not None else None try: try: result = get_hub().switch() assert result is self, 'Invalid switch into Semaphore.wait/acquire(): %r' % (result, ) except Timeout as ex: if ex is not timer: raise return ex finally: if timer is not None: timer.cancel() finally: self.unlink(switch)
def wait_write(fileno, timeout=-1): evt = write_event(fileno, _wait_helper, timeout, getcurrent()) try: switch_result = get_hub().switch() assert evt is switch_result, 'Invalid switch into wait_write(): %r' % (switch_result, ) finally: evt.cancel()
def get(self, block=True, timeout=None): """Return the stored value or raise the exception. If this instance already holds a value / an exception, return / raise it immediatelly. Otherwise, block until another greenlet calls :meth:`set` or :meth:`set_exception` or until the optional timeout occurs. 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). """ if self._exception is not _NONE: if self._exception is None: return self.value raise self._exception elif block: switch = getcurrent().switch self.rawlink(switch) try: timer = Timeout.start_new(timeout) try: result = self.hub.switch() assert result is self, 'Invalid switch into AsyncResult.get(): %r' % (result, ) finally: timer.cancel() except: self.unlink(switch) raise if self._exception is None: return self.value raise self._exception else: raise Timeout
def wait(self, timeout=None): """Block until the internal flag is true. If the internal flag is true on entry, return immediately. Otherwise, block until another thread calls :meth:`set` to set the flag to true, or until the optional timeout occurs. 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). Return the value of the internal flag (``True`` or ``False``). """ if self._flag: return self._flag else: switch = getcurrent().switch self.rawlink(switch) try: timer = Timeout.start_new(timeout) try: try: result = self.hub.switch() assert result is self, 'Invalid switch into Event.wait(): %r' % (result, ) except Timeout as ex: if ex is not timer: raise finally: timer.cancel() finally: self.unlink(switch) return self._flag
def __get_or_peek(self, method, block, timeout): # Internal helper method. The `method` should be either # self._get when called from self.get() or self._peek when # called from self.peek(). Call this after the initial check # to see if there are items in the queue. if self.hub is getcurrent(): # special case to make get_nowait() or peek_nowait() runnable in the mainloop greenlet # there are no items in the queue; try to fix the situation by unlocking putters while self.putters: # Note: get() used popleft(), peek used pop(); popleft # is almost certainly correct. self.putters.popleft().put_and_switch() if self.qsize(): return method() raise Empty() if not block: # We can't block, we're not the hub, and we have nothing # to return. No choice... raise Empty() waiter = Waiter() timeout = Timeout._start_new_or_dummy(timeout, Empty) try: self.getters.append(waiter) if self.putters: self._schedule_unlock() result = waiter.get() if result is not waiter: raise InvalidSwitchError('Invalid switch into Queue.get: %r' % (result, )) return method() finally: timeout.cancel() _safe_remove(self.getters, waiter)
def put(self, item, block=True, timeout=None): if self.hub is getcurrent(): if self.getters: getter = self.getters.popleft() getter.switch(item) return raise Full if not block: timeout = 0 waiter = Waiter() item = (item, waiter) self.putters.append(item) timeout = Timeout._start_new_or_dummy(timeout, Full) try: if self.getters: self._schedule_unlock() result = waiter.get() if result is not waiter: raise InvalidSwitchError("Invalid switch into Channel.put: %r" % (result, )) except: _safe_remove(self.putters, item) raise finally: timeout.cancel()
def get_socket(self, host, port): pid = os.getpid() if pid != self._pid: self._bootstrap(pid) greenlet = getcurrent() from_pool = True sock = self._used.get(greenlet) if sock is None: with self._lock: if self._count < self.pool_size: self._count += 1 from_pool = False sock = self.connect(host, port) if sock is None: from_pool = True sock = self._queue.get(timeout=self.network_timeout) if isinstance(greenlet, gevent.Greenlet): greenlet.link(self._return) self._used[greenlet] = sock else: ref = weakref.ref(greenlet, self._return) self._used[ref] = sock return sock, from_pool
def release(self): if self._owner is not getcurrent(): raise RuntimeError("cannot release un-aquired lock") self._count = count = self._count - 1 if not count: self._owner = None self._block.release()
def peek(self, block=True, timeout=None): if self.qsize(): if self.putters: self._schedule_unlock() return self._peek() elif not block and get_hub() is getcurrent(): # special case to make peek(False) runnable in the mainloop # greenlet there are no items in the queue; try to fix the # situation by unlocking putters while self.putters: putter = self.putters.pop() if putter: putter.switch(putter) if self.qsize(): return self._peek() raise Empty elif block: waiter = Waiter() timeout = Timeout.start_new(timeout, Empty) try: self.getters.add(waiter) if self.putters: self._schedule_unlock() result = waiter.get() assert result is waiter, "Invalid switch into Queue.put: %r" % (result,) return self._peek() finally: self.getters.discard(waiter) timeout.cancel() else: raise Empty
def acquire(self, blocking=1): tid = get_ident() gid = id(getcurrent()) tid_gid = (tid, gid) if tid_gid == self._owner: # We trust the GIL here so we can do this comparison w/o locking. self._count = self._count + 1 return True greenlet_lock = self._get_greenlet_lock() self._wait_queue.append(gid) # this is a safety in case an exception is raised somewhere and we must make sure we're not in the queue # otherwise it'll get stuck forever. remove_from_queue_on_return = True try: while True: if not greenlet_lock.acquire(blocking): return False # non-blocking and failed to acquire lock if self._wait_queue[0] == gid: # Hurray, we can have the lock. self._owner = tid_gid self._count = 1 remove_from_queue_on_return = False # don't remove us from the queue return True else: # we already hold the greenlet lock so obviously the owner is not in our thread. greenlet_lock.release() if blocking: sleep(0.0005) # 500 us -> initial delay of 1 ms else: return False finally: if remove_from_queue_on_return: self._wait_queue.remove(gid)
def wait(self, timeout=None): """Block until the instance is ready. If this instance already holds a value / an exception, return immediatelly. Otherwise, block until another thread calls :meth:`set` or :meth:`set_exception` or until the optional timeout occurs. 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). Return :attr:`value`. """ if self._exception is not _NONE: return self.value else: switch = getcurrent().switch self.rawlink(switch) try: timer = Timeout.start_new(timeout) try: result = self.hub.switch() assert result is self, 'Invalid switch into AsyncResult.wait(): %r' % (result, ) finally: timer.cancel() except Timeout as exc: self.unlink(switch) if exc is not timer: raise except: self.unlink(switch) raise # not calling unlink() in non-exception case, because if switch() # finished normally, link was already removed in _notify_links return self.value
def put(self, item, block=True, timeout=None): if self.hub is getcurrent(): if self.getters: getter = self.getters.popleft() getter.switch(item) return raise Full if not block: timeout = 0 waiter = Waiter() item = (item, waiter) self.putters.append(item) timeout = Timeout.start_new(timeout, Full) try: if self.getters: self._schedule_unlock() result = waiter.get() assert result is waiter, "Invalid switch into Channel.put: %r" % (result, ) except: self._discard(item) raise finally: timeout.cancel()
def acquire(self, blocking=True, timeout=None): if self.counter > 0: self.counter -= 1 return True elif not blocking: return False else: switch = getcurrent().switch self.rawlink(switch) try: timer = Timeout.start_new(timeout) try: try: result = self.hub.switch() assert result is self, "Invalid switch into Semaphore.acquire(): %r" % (result,) except Timeout: ex = sys.exc_info()[1] if ex is timer: return False raise finally: timer.cancel() finally: self.unlink(switch) self.counter -= 1 assert self.counter >= 0 return True
def peek(self, block=True, timeout=None): """Return an item from the queue without removing it. If optional args *block* is true and *timeout* is ``None`` (the default), block if necessary until an item is available. If *timeout* is a positive number, it blocks at most *timeout* seconds and raises the :class:`Empty` exception if no item was available within that time. Otherwise (*block* is false), return an item if one is immediately available, else raise the :class:`Empty` exception (*timeout* is ignored in that case). """ if self.qsize(): return self._peek() elif self.hub is getcurrent(): # special case to make peek(False) runnable in the mainloop greenlet # there are no items in the queue; try to fix the situation by unlocking putters while self.putters: self.putters.pop().put_and_switch() if self.qsize(): return self._peek() raise Empty elif block: waiter = Waiter() timeout = Timeout.start_new(timeout, Empty) try: self.getters.add(waiter) if self.putters: self._schedule_unlock() result = waiter.get() assert result is waiter, 'Invalid switch into Queue.peek: %r' % (result, ) return self._peek() finally: self.getters.discard(waiter) timeout.cancel() else: raise Empty
def _wait_core(self, timeout, catch=Timeout): # The core of the wait implementation, handling # switching and linking. If *catch* is set to (), # a timeout that elapses will be allowed to be raised. # Returns a true value if the wait succeeded without timing out. switch = getcurrent().switch self.rawlink(switch) try: timer = Timeout._start_new_or_dummy(timeout) try: try: result = self.hub.switch() if result is not self: # pragma: no cover raise InvalidSwitchError('Invalid switch into Event.wait(): %r' % (result, )) return True except catch as ex: if ex is not timer: raise # test_set_and_clear and test_timeout in test_threading # rely on the exact return values, not just truthish-ness return False finally: timer.cancel() finally: self.unlink(switch)
def unlink(self, receiver=None): """Remove the receiver set by :meth:`link` or :meth:`rawlink`""" if receiver is None: receiver = getcurrent() # discarding greenlets when we have GreenletLink instances in _links works, because # a GreenletLink instance pretends to be a greenlet, hash-wise and eq-wise self._links.discard(receiver)
def _is_owned(self): return self._owner is getcurrent()
def get_ident(gr=None): if gr is None: gr = getcurrent() return id(gr)
def _set_tstate_lock(self): self._greenlet = getcurrent()
def _apply_immediately(self): # If apply() is called from one of our own # worker greenlets, don't spawn a new one---if we're full, that # could deadlock. return getcurrent() in self
def __init__(self): _DummyThread_.__init__(self) g = getcurrent() rawlink = getattr(g, 'rawlink', None) if rawlink is not None: rawlink(_cleanup)
def _set_tstate_lock(self): super(Thread, self)._set_tstate_lock() greenlet = getcurrent() greenlet.rawlink(self.__greenlet_finished)
def get_dict(self): """Return the dict for the current thread. Raises KeyError if none defined.""" thread = getcurrent() return self.dicts[id(thread)][1]
def get_ident(gr=None): if gr is None: return id(getcurrent()) else: return id(gr)