Exemple #1
0
    def join(self, timeout=None):
        """Wait until the greenlet finishes or *timeout* expires.
        Return ``None`` regardless.
        """
        if self.ready():
            return

        switch = getcurrent().switch
        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
Exemple #2
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)
Exemple #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()
        item = (item, waiter)
        self.putters.append(item)
        timeout = Timeout.start_new(timeout, Full) if timeout is not None else None
        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:
            if timeout is not None:
                timeout.cancel()
Exemple #4
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)
Exemple #5
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(timeout) if timeout is not None else None
            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:
                if timer is not None:
                    timer.cancel()
        finally:
            self.unlink(switch)
        return self._flag
Exemple #6
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(timeout,
                                        Full) if timeout is not None else None
            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:
                if timeout is not None:
                    timeout.cancel()
                try:
                    self.putters.remove(waiter)
                except ValueError:
                    pass  # removed by unlock
        else:
            raise Full
Exemple #7
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
Exemple #8
0
    def get(self, block=True, timeout=None):
        """Remove and return an item from the queue.

        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():
            if self.putters:
                self._schedule_unlock()
            return self._get()
        elif self.hub is getcurrent():
            # special case to make get_nowait() 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.popleft().put_and_switch()
                if self.qsize():
                    return self._get()
            raise Empty
        elif block:
            waiter = Waiter()
            timeout = Timeout.start_new(timeout,
                                        Empty) if timeout is not None else None
            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 self._get()
            finally:
                if timeout is not None:
                    timeout.cancel()
                try:
                    self.getters.remove(waiter)
                except ValueError:
                    pass  # Removed by _unlock
        else:
            raise Empty
Exemple #9
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)
Exemple #10
0
    def get(self, block=True, timeout=None):
        """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
        self.rawlink(switch)
        try:
            t = Timeout.start_new(timeout) if timeout is not None else None
            try:
                result = self.parent.switch()
                if result is not self:
                    raise InvalidSwitchError(
                        'Invalid switch into Greenlet.get(): %r' % (result, ))
            finally:
                if t is not None:
                    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()