def _wait_core(self, timeout, catch=Timeout):
        """
        The core of the wait implementation, handling switching and
        linking.

        This method is NOT safe to call from multiple threads.

        ``self.hub`` must be initialized before entering this method.
        The hub that is set is considered the owner and cannot be changed
        while this method is running. It must only be called from the thread
        where ``self.hub`` is the current hub.

        If *catch* is set to ``()``, a timeout that elapses will be
        allowed to be raised.

        :return: A true value if the wait succeeded without timing out.
          That is, a true return value means we were notified and control
          resumed in this greenlet.
        """
        with Timeout._start_new_or_dummy(timeout) as timer:  # Might release
            # We already checked above (_wait()) if we're ready()
            try:
                self.__wait_to_be_notified(
                    True,  # Use rawlink()
                )
                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
Beispiel #2
0
    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 no timeout was given, the only possible return value is ``True``.)
        """
        if self._flag:
            return self._flag

        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:
                        raise InvalidSwitchError('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
Beispiel #3
0
    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()  # pylint:disable=undefined-variable
        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()
Beispiel #4
0
    def connect(self, address):
        if self.timeout == 0.0:
            return _socket.socket.connect(self._sock, address)
        address = _socketcommon._resolve_addr(self._sock, address)

        with Timeout._start_new_or_dummy(self.timeout, timeout("timed out")):
            while True:
                err = self.getsockopt(SOL_SOCKET, SO_ERROR)
                if err:
                    raise error(err, strerror(err))
                result = _socket.socket.connect_ex(self._sock, address)

                if not result or result == EISCONN:
                    break
                elif (result in (EWOULDBLOCK, EINPROGRESS,
                                 EALREADY)) or (result == EINVAL
                                                and is_windows):
                    self._wait(self._write_event)
                else:
                    if (isinstance(address, tuple) and address[0] == 'fe80::1'
                            and result == EHOSTUNREACH):
                        # On Python 3.7 on mac, we see EHOSTUNREACH
                        # returned for this link-local address, but it really is
                        # supposed to be ECONNREFUSED according to the standard library
                        # tests (test_socket.NetworkConnectionNoServer.test_create_connection)
                        # (On previous versions, that code passed the '127.0.0.1' IPv4 address, so
                        # ipv6 link locals were never a factor; 3.7 passes 'localhost'.)
                        # It is something of a mystery how the stdlib socket code doesn't
                        # produce EHOSTUNREACH---I (JAM) can't see how socketmodule.c would avoid
                        # that. The normal connect just calls connect_ex much like we do.
                        result = ECONNREFUSED
                    raise error(result, strerror(result))
Beispiel #5
0
    def join(self, timeout=None):
        """
        join(timeout=None) -> None

        Wait until the greenlet finishes or *timeout* expires. Return
        ``None`` regardless.
        """
        if self.ready():
            return

        switch = getcurrent().switch # pylint:disable=undefined-variable
        self.rawlink(switch)
        try:
            t = Timeout._start_new_or_dummy(timeout)
            try:
                result = self.parent.switch()
                if result is not self:
                    raise InvalidSwitchError('Invalid switch into Greenlet.join(): %r' % (result, ))
            finally:
                t.cancel()
        except Timeout as ex:
            self.unlink(switch)
            if ex is not t:
                raise
        except:
            self.unlink(switch)
            raise
Beispiel #6
0
    def _wait_core(self, timeout, catch=Timeout):
        """
        The core of the wait implementation, handling switching and
        linking.

        This method is safe to call from multiple threads; it must be holding
        the GIL for the entire duration, or be protected by a Python-level
        lock for that to be true.

        ``self.hub`` must be initialized before entering this method.
        The hub that is set is considered the owner and cannot be changed.

        If *catch* is set to ``()``, a timeout that elapses will be
        allowed to be raised.

        :return: A true value if the wait succeeded without timing out.
          That is, a true return value means we were notified and control
          resumed in this greenlet.
        """
        with Timeout._start_new_or_dummy(timeout) as timer:  # Might release
            try:
                self.__wait_to_be_notified(True)  # Use rawlink()
                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
Beispiel #7
0
 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  # pylint:disable=undefined-variable
     self.rawlink(switch)
     try:
         with Timeout._start_new_or_dummy(timeout) as timer:
             try:
                 if self.hub is None:
                     self.hub = get_hub()
                 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:
         self.unlink(switch)
Beispiel #8
0
    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)
Beispiel #9
0
    def connect(self, address):
        if self.timeout == 0.0:
            return self._sock.connect(address)
        sock = self._sock
        if isinstance(address, tuple):
            r = getaddrinfo(address[0], address[1], sock.family)
            address = r[0][-1]

        timer = Timeout._start_new_or_dummy(self.timeout, timeout('timed out'))
        try:
            while True:
                err = sock.getsockopt(SOL_SOCKET, SO_ERROR)
                if err:
                    raise error(err, strerror(err))
                result = sock.connect_ex(address)
                if not result or result == EISCONN:
                    break
                elif (result in (EWOULDBLOCK, EINPROGRESS,
                                 EALREADY)) or (result == EINVAL
                                                and is_windows):
                    self._wait(self._write_event)
                else:
                    raise error(result, strerror(result))
        finally:
            timer.close()
Beispiel #10
0
    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)
Beispiel #11
0
    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()
Beispiel #12
0
 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)
Beispiel #13
0
    def connect(self, address):
        """
        Connect to *address*.

        .. versionchanged:: 20.6.0
            If the host part of the address includes an IPv6 scope ID,
            it will be used instead of ignored, if the platform supplies
            :func:`socket.inet_pton`.
        """
        if self.timeout == 0.0:
            return self._sock.connect(address)

        address = _socketcommon._resolve_addr(self._sock, address)

        timer = Timeout._start_new_or_dummy(self.timeout, timeout('timed out'))
        try:
            while 1:
                err = self._sock.getsockopt(SOL_SOCKET, SO_ERROR)
                if err:
                    raise error(err, strerror(err))
                result = self._sock.connect_ex(address)
                if not result or result == EISCONN:
                    break
                if (result in (EWOULDBLOCK, EINPROGRESS,
                               EALREADY)) or (result == EINVAL and is_windows):
                    self._wait(self._write_event)
                else:
                    raise error(result, strerror(result))
        finally:
            timer.close()
Beispiel #14
0
 def kill(self, exception=GreenletExit, block=True, timeout=None):
     """
     Kill all greenlets being tracked by this group.
     """
     timer = Timeout._start_new_or_dummy(timeout)
     try:
         while self.greenlets:
             for greenlet in list(self.greenlets):
                 if greenlet in self.dying:
                     continue
                 try:
                     kill = greenlet.kill
                 except AttributeError:
                     _kill(greenlet, exception)
                 else:
                     kill(exception, block=False)
                 self.dying.add(greenlet)
             if not block:
                 break
             joinall(self.greenlets)
     except Timeout as ex:
         if ex is not timer:
             raise
     finally:
         timer.cancel()
Beispiel #15
0
def wait(io, timeout=None, timeout_exc=_NONE):
    """
    Block the current greenlet until *io* is ready.

    If *timeout* is non-negative, then *timeout_exc* is raised after
    *timeout* second has passed. By default *timeout_exc* is
    ``socket.timeout('timed out')``.

    If :func:`cancel_wait` is called on *io* by another greenlet,
    raise an exception in this blocking greenlet
    (``socket.error(EBADF, 'File descriptor was closed in another
    greenlet')`` by default).

    :param io: A libev watcher, most commonly an IO watcher obtained from
        :meth:`gevent.core.loop.io`
    :keyword timeout_exc: The exception to raise if the timeout expires.
        By default, a :class:`socket.timeout` exception is raised.
        If you pass a value for this keyword, it is interpreted as for
        :class:`gevent.timeout.Timeout`.
    """
    if io.callback is not None:
        raise ConcurrentObjectUseError(
            'This socket is already used by another greenlet: %r' %
            (io.callback, ))
    timeout = Timeout._start_new_or_dummy(
        timeout, (timeout_exc if timeout_exc is not _NONE or timeout is None
                  else _timeout_error('timed out')))

    with timeout:
        return get_hub().wait(io)
Beispiel #16
0
 def kill(self, exception=GreenletExit, block=True, timeout=None):
     """
     Kill all greenlets being tracked by this group.
     """
     timer = Timeout._start_new_or_dummy(timeout)
     try:
         try:
             while self.greenlets:
                 for greenlet in list(self.greenlets):
                     if greenlet not in self.dying:
                         try:
                             kill = greenlet.kill
                         except AttributeError:
                             _kill(greenlet, exception)
                         else:
                             kill(exception, block=False)
                         self.dying.add(greenlet)
                 if not block:
                     break
                 joinall(self.greenlets)
         except Timeout as ex:
             if ex is not timer:
                 raise
     finally:
         timer.cancel()
Beispiel #17
0
    def connect(self, address):
        if self.timeout == 0.0:
            return _socket.socket.connect(self._sock, address)
        address = _socketcommon._resolve_addr(self._sock, address)

        with Timeout._start_new_or_dummy(self.timeout, timeout("timed out")):
            while True:
                err = self.getsockopt(SOL_SOCKET, SO_ERROR)
                if err:
                    raise error(err, strerror(err))
                result = _socket.socket.connect_ex(self._sock, address)

                if not result or result == EISCONN:
                    break
                elif (result in (EWOULDBLOCK, EINPROGRESS, EALREADY)) or (result == EINVAL and is_windows):
                    self._wait(self._write_event)
                else:
                    if (isinstance(address, tuple)
                            and address[0] == 'fe80::1'
                            and result == EHOSTUNREACH):
                        # On Python 3.7 on mac, we see EHOSTUNREACH
                        # returned for this link-local address, but it really is
                        # supposed to be ECONNREFUSED according to the standard library
                        # tests (test_socket.NetworkConnectionNoServer.test_create_connection)
                        # (On previous versions, that code passed the '127.0.0.1' IPv4 address, so
                        # ipv6 link locals were never a factor; 3.7 passes 'localhost'.)
                        # It is something of a mystery how the stdlib socket code doesn't
                        # produce EHOSTUNREACH---I (JAM) can't see how socketmodule.c would avoid
                        # that. The normal connect just calls connect_ex much like we do.
                        result = ECONNREFUSED
                    raise error(result, strerror(result))
Beispiel #18
0
    def join(self, timeout=None):
        """
        join(timeout=None) -> None

        Wait until the greenlet finishes or *timeout* expires. Return
        ``None`` regardless.
        """
        if self.ready():
            return

        switch = getcurrent().switch  # pylint:disable=undefined-variable
        self.rawlink(switch)
        try:
            t = Timeout._start_new_or_dummy(timeout)
            try:
                result = self.parent.switch()
                if result is not self:
                    raise InvalidSwitchError(
                        'Invalid switch into Greenlet.join(): %r' % (result, ))
            finally:
                t.cancel()
        except Timeout as ex:
            self.unlink(switch)
            if ex is not t:
                raise
        except:
            self.unlink(switch)
            raise
Beispiel #19
0
    def wait(self, timeout=None):
        """Block until the instance is ready.

        If this instance already holds a value, it is returned immediately. If this
        instance already holds an exception, ``None`` is returned immediately.

        Otherwise, block until another greenlet calls :meth:`set` or :meth:`set_exception`
        (at which point either the value or ``None`` will be returned, respectively),
        or until the optional timeout expires (at which point ``None`` will also be
        returned).

        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).

        .. note:: If a timeout is given and expires, ``None`` will be returned
            (no timeout exception will be raised).

        """
        if self.ready():
            return self.value

        switch = getcurrent().switch
        self.rawlink(switch)
        try:
            timer = Timeout._start_new_or_dummy(timeout)
            try:
                result = self.hub.switch()
                if result is not self:
                    raise InvalidSwitchError(
                        '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
Beispiel #20
0
def killall(greenlets, exception=GreenletExit, block=True, timeout=None):
    """
    Forceably terminate all the ``greenlets`` by causing them to raise ``exception``.

    .. caution:: Use care when killing greenlets. If they are not prepared for exceptions,
       this could result in corrupted state.

    :param greenlets: A **bounded** iterable of the non-None greenlets to terminate.
       *All* the items in this iterable must be greenlets that belong to the same hub,
       which should be the hub for this current thread.
    :keyword exception: The exception to raise in the greenlets. By default this is
        :class:`GreenletExit`.
    :keyword bool block: If True (the default) then this function only returns when all the
        greenlets are dead; the current greenlet is unscheduled during that process.
        If greenlets ignore the initial exception raised in them,
        then they will be joined (with :func:`gevent.joinall`) and allowed to die naturally.
        If False, this function returns immediately and greenlets will raise
        the exception asynchronously.
    :keyword float timeout: A time in seconds to wait for greenlets to die. If given, it is
        only honored when ``block`` is True.
    :raise Timeout: If blocking and a timeout is given that elapses before
        all the greenlets are dead.

    .. versionchanged:: 1.1a2
        *greenlets* can be any iterable of greenlets, like an iterator or a set.
        Previously it had to be a list or tuple.
    """
    # support non-indexable containers like iterators or set objects
    greenlets = list(greenlets)
    if not greenlets:
        return
    loop = greenlets[0].loop
    if block:
        waiter = Waiter() # pylint:disable=undefined-variable
        loop.run_callback(_killall3, greenlets, exception, waiter)
        t = Timeout._start_new_or_dummy(timeout)
        try:
            alive = waiter.get()
            if alive:
                joinall(alive, raise_error=False)
        finally:
            t.cancel()
    else:
        loop.run_callback(_killall, greenlets, exception)
Beispiel #21
0
def killall(greenlets, exception=GreenletExit, block=True, timeout=None):
    """
    Forceably terminate all the ``greenlets`` by causing them to raise ``exception``.

    .. caution:: Use care when killing greenlets. If they are not prepared for exceptions,
       this could result in corrupted state.

    :param greenlets: A **bounded** iterable of the non-None greenlets to terminate.
       *All* the items in this iterable must be greenlets that belong to the same hub,
       which should be the hub for this current thread.
    :keyword exception: The exception to raise in the greenlets. By default this is
        :class:`GreenletExit`.
    :keyword bool block: If True (the default) then this function only returns when all the
        greenlets are dead; the current greenlet is unscheduled during that process.
        If greenlets ignore the initial exception raised in them,
        then they will be joined (with :func:`gevent.joinall`) and allowed to die naturally.
        If False, this function returns immediately and greenlets will raise
        the exception asynchronously.
    :keyword float timeout: A time in seconds to wait for greenlets to die. If given, it is
        only honored when ``block`` is True.
    :raise Timeout: If blocking and a timeout is given that elapses before
        all the greenlets are dead.

    .. versionchanged:: 1.1a2
        *greenlets* can be any iterable of greenlets, like an iterator or a set.
        Previously it had to be a list or tuple.
    """
    # support non-indexable containers like iterators or set objects
    greenlets = list(greenlets)
    if not greenlets:
        return
    loop = greenlets[0].loop
    if block:
        waiter = Waiter()  # pylint:disable=undefined-variable
        loop.run_callback(_killall3, greenlets, exception, waiter)
        t = Timeout._start_new_or_dummy(timeout)
        try:
            alive = waiter.get()
            if alive:
                joinall(alive, raise_error=False)
        finally:
            t.cancel()
    else:
        loop.run_callback(_killall, greenlets, exception)
Beispiel #22
0
    def get(self, block=True, timeout=None):
        """
        get(block=True, timeout=None) -> object

        Return the result the greenlet has returned or re-raise the
        exception it has raised.

        If block is ``False``, raise :class:`gevent.Timeout` if the
        greenlet is still alive. If block is ``True``, unschedule the
        current greenlet until the result is available or the timeout
        expires. In the latter cases, :class:`gevent.Timeout` is
        raised.
        """
        if self.ready():
            if self.successful():
                return self.value
            self._raise_exception()
        if not block:
            raise Timeout()

        switch = getcurrent().switch  # pylint:disable=undefined-variable
        self.rawlink(switch)
        try:
            t = Timeout._start_new_or_dummy(timeout)
            try:
                result = self.parent.switch()
                if result is not self:
                    raise InvalidSwitchError(
                        'Invalid switch into Greenlet.get(): %r' % (result, ))
            finally:
                t.cancel()
        except:
            # unlinking in 'except' instead of finally is an optimization:
            # if switch occurred normally then link was already removed in _notify_links
            # and there's no need to touch the links set.
            # Note, however, that if "Invalid switch" assert was removed and invalid switch
            # did happen, the link would remain, causing another invalid switch later in this greenlet.
            self.unlink(switch)
            raise

        if self.ready():
            if self.successful():
                return self.value
            self._raise_exception()
Beispiel #23
0
    def get(self, block=True, timeout=None):
        """
        get(block=True, timeout=None) -> object

        Return the result the greenlet has returned or re-raise the
        exception it has raised.

        If block is ``False``, raise :class:`gevent.Timeout` if the
        greenlet is still alive. If block is ``True``, unschedule the
        current greenlet until the result is available or the timeout
        expires. In the latter case, :class:`gevent.Timeout` is
        raised.
        """
        if self.ready():
            if self.successful():
                return self.value
            self._raise_exception()
        if not block:
            raise Timeout()

        switch = getcurrent().switch # pylint:disable=undefined-variable
        self.rawlink(switch)
        try:
            t = Timeout._start_new_or_dummy(timeout)
            try:
                result = self.parent.switch()
                if result is not self:
                    raise InvalidSwitchError('Invalid switch into Greenlet.get(): %r' % (result, ))
            finally:
                t.cancel()
        except:
            # unlinking in 'except' instead of finally is an optimization:
            # if switch occurred normally then link was already removed in _notify_links
            # and there's no need to touch the links set.
            # Note, however, that if "Invalid switch" assert was removed and invalid switch
            # did happen, the link would remain, causing another invalid switch later in this greenlet.
            self.unlink(switch)
            raise

        if self.ready():
            if self.successful():
                return self.value
            self._raise_exception()
Beispiel #24
0
    def put(self, item, block=True, timeout=None):
        """Put an item into the queue.

        If optional arg *block* is true and *timeout* is ``None`` (the default),
        block if necessary until a free slot is available. If *timeout* is
        a positive number, it blocks at most *timeout* seconds and raises
        the :class:`Full` exception if no free slot was available within that time.
        Otherwise (*block* is false), put an item on the queue if a free slot
        is immediately available, else raise the :class:`Full` exception (*timeout*
        is ignored in that case).
        """
        if self._maxsize == -1 or self.qsize() < self._maxsize:
            # there's a free slot, put an item right away
            self._put(item)
            if self.getters:
                self._schedule_unlock()
        elif self.hub is getcurrent():
            # We're in the mainloop, so we cannot wait; we can switch to other greenlets though.
            # Check if possible to get a free slot in the queue.
            while self.getters and self.qsize(
            ) and self.qsize() >= self._maxsize:
                getter = self.getters.popleft()
                getter.switch(getter)
            if self.qsize() < self._maxsize:
                self._put(item)
                return
            raise Full
        elif block:
            waiter = ItemWaiter(item, self)
            self.putters.append(waiter)
            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 Queue.put: %r" % (result, ))
            finally:
                timeout.cancel()
                _safe_remove(self.putters, waiter)
        else:
            raise Full
def _primitive_wait(watcher, timeout, timeout_exc, hub):
    if watcher.callback is not None:
        raise ConcurrentObjectUseError(
            'This socket is already used by another greenlet: %r' %
            (watcher.callback, ))

    if hub is None:
        hub = get_hub()

    if timeout is None:
        hub.wait(watcher)
        return

    timeout = Timeout._start_new_or_dummy(
        timeout, (timeout_exc if timeout_exc is not _NONE or timeout is None
                  else _timeout_error('timed out')))

    with timeout:
        hub.wait(watcher)
Beispiel #26
0
    def wait(self, timeout=None):
        """Block until the instance is ready.

        If this instance already holds a value, it is returned immediately. If this
        instance already holds an exception, ``None`` is returned immediately.

        Otherwise, block until another greenlet calls :meth:`set` or :meth:`set_exception`
        (at which point either the value or ``None`` will be returned, respectively),
        or until the optional timeout expires (at which point ``None`` will also be
        returned).

        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).

        .. note:: If a timeout is given and expires, ``None`` will be returned
            (no timeout exception will be raised).

        """
        if self.ready():
            return self.value

        switch = getcurrent().switch
        self.rawlink(switch)
        try:
            timer = Timeout._start_new_or_dummy(timeout)
            try:
                result = self.hub.switch()
                if result is not self:
                    raise InvalidSwitchError('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
Beispiel #27
0
def _primitive_wait(watcher, timeout, timeout_exc, hub):
    if watcher.callback is not None:
        raise ConcurrentObjectUseError('This socket is already used by another greenlet: %r'
                                       % (watcher.callback, ))

    if hub is None:
        hub = get_hub()

    if timeout is None:
        hub.wait(watcher)
        return

    timeout = Timeout._start_new_or_dummy(
        timeout,
        (timeout_exc
         if timeout_exc is not _NONE or timeout is None
         else _timeout_error('timed out')))

    with timeout:
        hub.wait(watcher)
Beispiel #28
0
    def __acquire_using_two_hubs(self,
                                 hub_for_this_thread,
                                 current_greenlet,
                                 timeout):
        # Allocating and starting the watcher *could* release the GIL.
        # with the libev corcext, allocating won't, but starting briefly will.
        # With other backends, allocating might, and starting might also.
        # So...
        watcher = hub_for_this_thread.loop.async_()
        send = watcher.send_ignoring_arg
        watcher.start(current_greenlet.switch, self)
        try:
            with Timeout._start_new_or_dummy(timeout) as timer:
                # ... now that we're back holding the GIL, we need to verify our
                # state.
                try:
                    while 1:
                        if self.counter > 0:
                            self.counter -= 1
                            assert self.counter >= 0, (self,)
                            return True

                        self.__add_link(send)

                        # Releases the object lock
                        self._switch_to_hub(hub_for_this_thread)
                        # We waited and got notified. We should be ready now, so a non-blocking
                        # acquire() should succeed. But sometimes we get spurious notifications?
                        # It's not entirely clear how. So we need to loop until we get it, or until
                        # the timer expires
                        result = self.acquire(0)
                        if result:
                            return result
                except Timeout as tex:
                    if tex is not timer:
                        raise
                    return False
        finally:
            self._quiet_unlink_all(send)
            watcher.stop()
            watcher.close()
Beispiel #29
0
    def put(self, item, block=True, timeout=None):
        """Put an item into the queue.

        If optional arg *block* is true and *timeout* is ``None`` (the default),
        block if necessary until a free slot is available. If *timeout* is
        a positive number, it blocks at most *timeout* seconds and raises
        the :class:`Full` exception if no free slot was available within that time.
        Otherwise (*block* is false), put an item on the queue if a free slot
        is immediately available, else raise the :class:`Full` exception (*timeout*
        is ignored in that case).
        """
        if self.maxsize is None or self.qsize() < self.maxsize:
            # there's a free slot, put an item right away
            self._put(item)
            if self.getters:
                self._schedule_unlock()
        elif self.hub is getcurrent():
            # We're in the mainloop, so we cannot wait; we can switch to other greenlets though.
            # Check if possible to get a free slot in the queue.
            while self.getters and self.qsize() and self.qsize() >= self.maxsize:
                getter = self.getters.popleft()
                getter.switch(getter)
            if self.qsize() < self.maxsize:
                self._put(item)
                return
            raise Full
        elif block:
            waiter = ItemWaiter(item, self)
            self.putters.append(waiter)
            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 Queue.put: %r" % (result, ))
            finally:
                timeout.cancel()
                _safe_remove(self.putters, waiter)
        else:
            raise Full
Beispiel #30
0
    def get(self, block=True, timeout=None):
        """Return the stored value or raise the exception.

        If this instance already holds a value or an exception, return  or 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).

        :keyword bool block: If set to ``False`` and this instance is not ready,
            immediately raise a :class:`Timeout` exception.
        """
        if self._value is not _NONE:
            return self._value
        if self._exc_info:
            return self._raise_exception()

        if not block:
            # Not ready and not blocking, so immediately timeout
            raise Timeout()

        switch = getcurrent().switch
        self.rawlink(switch)
        try:
            timer = Timeout._start_new_or_dummy(timeout)
            try:
                result = self.hub.switch()
                if result is not self:
                    raise InvalidSwitchError(
                        'Invalid switch into AsyncResult.get(): %r' %
                        (result, ))
            finally:
                timer.cancel()
        except:
            self.unlink(switch)
            raise

        # by definition we are now ready
        return self.get(block=False)
Beispiel #31
0
    def connect(self, address):
        if self.timeout == 0.0:
            return self._sock.connect(address)

        address = _socketcommon._resolve_addr(self._sock, address)

        timer = Timeout._start_new_or_dummy(self.timeout, timeout('timed out'))
        try:
            while 1:
                err = self._sock.getsockopt(SOL_SOCKET, SO_ERROR)
                if err:
                    raise error(err, strerror(err))
                result = self._sock.connect_ex(address)
                if not result or result == EISCONN:
                    break
                elif (result in (EWOULDBLOCK, EINPROGRESS, EALREADY)) or (result == EINVAL and is_windows):
                    self._wait(self._write_event)
                else:
                    raise error(result, strerror(result))
        finally:
            timer.close()
Beispiel #32
0
    def connect(self, address):
        if self.timeout == 0.0:
            return self._sock.connect(address)

        address = _socketcommon._resolve_addr(self._sock, address)

        timer = Timeout._start_new_or_dummy(self.timeout, timeout('timed out'))
        try:
            while 1:
                err = self._sock.getsockopt(SOL_SOCKET, SO_ERROR)
                if err:
                    raise error(err, strerror(err))
                result = self._sock.connect_ex(address)
                if not result or result == EISCONN:
                    break
                elif (result in (EWOULDBLOCK, EINPROGRESS, EALREADY)) or (result == EINVAL and is_windows):
                    self._wait(self._write_event)
                else:
                    raise error(result, strerror(result))
        finally:
            timer.close()
Beispiel #33
0
    def connect(self, address):
        """
        Connect to *address*.

        .. versionchanged:: 20.6.0
            If the host part of the address includes an IPv6 scope ID,
            it will be used instead of ignored, if the platform supplies
            :func:`socket.inet_pton`.
        """
        if self.timeout == 0.0:
            return self._sock.connect(address)
        address = _resolve_addr(self._sock, address)
        with Timeout._start_new_or_dummy(self.timeout,
                                         __socket__.timeout("timed out")):
            while 1:
                err = self.getsockopt(__socket__.SOL_SOCKET,
                                      __socket__.SO_ERROR)
                if err:
                    raise _SocketError(err, strerror(err))
                result = self._sock.connect_ex(address)

                if not result or result == EISCONN:
                    break
                if (result in (EWOULDBLOCK, EINPROGRESS,
                               EALREADY)) or (result == EINVAL and is_windows):
                    self._wait(self._write_event)
                else:
                    if (isinstance(address, tuple) and address[0] == 'fe80::1'
                            and result == EHOSTUNREACH):
                        # On Python 3.7 on mac, we see EHOSTUNREACH
                        # returned for this link-local address, but it really is
                        # supposed to be ECONNREFUSED according to the standard library
                        # tests (test_socket.NetworkConnectionNoServer.test_create_connection)
                        # (On previous versions, that code passed the '127.0.0.1' IPv4 address, so
                        # ipv6 link locals were never a factor; 3.7 passes 'localhost'.)
                        # It is something of a mystery how the stdlib socket code doesn't
                        # produce EHOSTUNREACH---I (JAM) can't see how socketmodule.c would avoid
                        # that. The normal connect just calls connect_ex much like we do.
                        result = ECONNREFUSED
                    raise _SocketError(result, strerror(result))
Beispiel #34
0
    def get(self, block=True, timeout=None):
        if self.hub is getcurrent():
            if self.putters:
                item, putter = self.putters.popleft()
                self.hub.loop.run_callback(putter.switch, putter)
                return item

        if not block:
            timeout = 0

        waiter = Waiter()  # pylint:disable=undefined-variable
        timeout = Timeout._start_new_or_dummy(timeout, Empty)
        try:
            self.getters.append(waiter)
            if self.putters:
                self._schedule_unlock()
            return waiter.get()
        except:
            self.getters.remove(waiter)
            raise
        finally:
            timeout.close()
Beispiel #35
0
    def get(self, block=True, timeout=None):
        """Return the stored value or raise the exception.

        If this instance already holds a value or an exception, return  or 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).

        :keyword bool block: If set to ``False`` and this instance is not ready,
            immediately raise a :class:`Timeout` exception.
        """
        if self._value is not _NONE:
            return self._value
        if self._exc_info:
            return self._raise_exception()

        if not block:
            # Not ready and not blocking, so immediately timeout
            raise Timeout()

        switch = getcurrent().switch
        self.rawlink(switch)
        try:
            timer = Timeout._start_new_or_dummy(timeout)
            try:
                result = self.hub.switch()
                if result is not self:
                    raise InvalidSwitchError('Invalid switch into AsyncResult.get(): %r' % (result, ))
            finally:
                timer.cancel()
        except:
            self.unlink(switch)
            raise

        # by definition we are now ready
        return self.get(block=False)
Beispiel #36
0
    def get(self, block=True, timeout=None):
        if self.hub is getcurrent():
            if self.putters:
                item, putter = self.putters.popleft()
                self.hub.loop.run_callback(putter.switch, putter)
                return item

        if not block:
            timeout = 0

        waiter = Waiter()
        timeout = Timeout._start_new_or_dummy(timeout, Empty)
        try:
            self.getters.append(waiter)
            if self.putters:
                self._schedule_unlock()
            return waiter.get()
        except:
            self.getters.remove(waiter)
            raise
        finally:
            timeout.cancel()
Beispiel #37
0
 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:
         timer = Timeout._start_new_or_dummy(timeout)
         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:
             timer.cancel()
     finally:
         self.unlink(switch)
 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:
         timer = Timeout._start_new_or_dummy(timeout)
         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:
             timer.cancel()
     finally:
         self.unlink(switch)
Beispiel #39
0
    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 (greenlet) 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 no timeout was given, the only possible return value is ``True``.)
        """
        if self._flag:
            return self._flag

        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:
                        raise InvalidSwitchError(
                            '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
Beispiel #40
0
def killall(greenlets, exception=GreenletExit, block=True, timeout=None):
    """
    Forceably terminate all the *greenlets* by causing them to raise *exception*.

    .. caution:: Use care when killing greenlets. If they are not prepared for exceptions,
       this could result in corrupted state.

    :param greenlets: A **bounded** iterable of the non-None greenlets to terminate.
       *All* the items in this iterable must be greenlets that belong to the same hub,
       which should be the hub for this current thread. If this is a generator or iterator
       that switches greenlets, the results are undefined.
    :keyword exception: The type of exception to raise in the greenlets. By default this is
        :class:`GreenletExit`.
    :keyword bool block: If True (the default) then this function only returns when all the
        greenlets are dead; the current greenlet is unscheduled during that process.
        If greenlets ignore the initial exception raised in them,
        then they will be joined (with :func:`gevent.joinall`) and allowed to die naturally.
        If False, this function returns immediately and greenlets will raise
        the exception asynchronously.
    :keyword float timeout: A time in seconds to wait for greenlets to die. If given, it is
        only honored when ``block`` is True.
    :raise Timeout: If blocking and a timeout is given that elapses before
        all the greenlets are dead.

    .. versionchanged:: 1.1a2
        *greenlets* can be any iterable of greenlets, like an iterator or a set.
        Previously it had to be a list or tuple.
    .. versionchanged:: 1.5a3
        Any :class:`Greenlet` in the *greenlets* list that hadn't been switched to before
        calling this method will never be switched to. This makes this function
        behave like :meth:`Greenlet.kill`. This does not apply to raw greenlets.
    .. versionchanged:: 1.5a3
       Now accepts raw greenlets created by :func:`gevent.spawn_raw`.
    """

    need_killed = []  # type: list
    for glet in greenlets:
        # Quick pass through to prevent any greenlet from
        # actually being switched to if it hasn't already.
        # (Previously we called ``list(greenlets)`` so we're still
        # linear.)
        #
        # We don't use glet.kill() here because we don't want to schedule
        # any callbacks in the loop; we're about to handle that more directly.
        try:
            cancel = glet._maybe_kill_before_start
        except AttributeError:
            need_killed.append(glet)
        else:
            if not cancel(exception):
                need_killed.append(glet)

    if not need_killed:
        return

    loop = glet.loop  # pylint:disable=undefined-loop-variable
    if block:
        waiter = Waiter()  # pylint:disable=undefined-variable
        loop.run_callback(_killall3, need_killed, exception, waiter)
        t = Timeout._start_new_or_dummy(timeout)
        try:
            alive = waiter.get()
            if alive:
                joinall(alive, raise_error=False)
        finally:
            t.cancel()
    else:
        loop.run_callback(_killall, need_killed, exception)