Exemple #1
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()
Exemple #2
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)
Exemple #3
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
Exemple #4
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() # pylint:disable=undefined-variable
        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 _switch_to_hub(self, the_hub):
     self._drop_lock_for_switch_out()
     try:
         result = the_hub.switch()
     finally:
         self._acquire_lock_for_switch_in()
     if result is not self:  # pragma: no cover
         raise InvalidSwitchError('Invalid switch into %s.wait(): %r' % (
             self.__class__.__name__,
             result,
         ))
Exemple #6
0
    def _wait(self, timeout=None):
        if self.ready():
            result = self._wait_return_value(False, False)  # pylint:disable=assignment-from-none
            if self._notifier:
                # We're already notifying waiters; one of them must have run
                # and switched to us.
                switch = getcurrent().switch  # pylint:disable=undefined-variable
                self._notifier.args[0].append(switch)
                switch_result = self.hub.switch()
                if switch_result is not self:  # pragma: no cover
                    raise InvalidSwitchError(
                        'Invalid switch into Event.wait(): %r' % (result, ))

            return result

        gotit = self._wait_core(timeout)
        return self._wait_return_value(True, gotit)
    def wait(self, watcher):
        """
        Wait until the *watcher* (which must not be started) is ready.

        The current greenlet will be unscheduled during this time.
        """
        waiter = Waiter(self)  # pylint:disable=undefined-variable
        watcher.start(waiter.switch, waiter)
        try:
            result = waiter.get()
            if result is not waiter:
                raise InvalidSwitchError(
                    'Invalid switch into %s: %r (expected %r)' % (
                        getcurrent(),  # pylint:disable=undefined-variable
                        result,
                        waiter))
        finally:
            watcher.stop()
Exemple #8
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()
Exemple #9
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
Exemple #10
0
    def __wait_to_be_notified(self, rawlink):  # pylint:disable=too-many-branches
        # We've got to watch where we could potentially release the GIL.
        # Decisions we make based an the state of this object must be in blocks
        # that cannot release the GIL.
        resume_this_greenlet = None
        watcher = None
        current_hub = get_hub()
        send = None

        while 1:
            my_hub = self.hub
            if my_hub is current_hub:
                break

            # We're owned by another hub.
            if my_hub.dead:  # dead is a property, this could have released the GIL.
                # We have the GIL back. Did anything change?
                if my_hub is not self.hub:
                    continue  # start over.
                # The other hub is dead, so we can take ownership.
                self.hub = current_hub
                break
            # Some other hub owns this object. We must ask it to wake us
            # up. We can't use a Python-level ``Lock`` because
            # (1) it doesn't support a timeout on all platforms; and
            # (2) we don't want to block this hub from running. So we need to
            # do so in a way that cooperates with *two* hubs. That's what an
            # async watcher is built for.
            #
            # 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...XXX: Race condition here, tiny though it may be.
            watcher = current_hub.loop.async_()
            send = watcher.send_ignoring_arg
            if rawlink:
                # Make direct calls to self.rawlink, the most common case,
                # so cython can more easily optimize.
                self.rawlink(send)
            else:
                self._notifier.args[0].append(send)

            watcher.start(getcurrent().switch, self)  # pylint:disable=undefined-variable
            break

        if self.hub is current_hub:
            resume_this_greenlet = getcurrent().switch  # pylint:disable=undefined-variable
            if rawlink:
                self.rawlink(resume_this_greenlet)
            else:
                self._notifier.args[0].append(resume_this_greenlet)
        try:
            self._drop_lock_for_switch_out()
            result = current_hub.switch()  # Probably releases
            # If we got here, we were automatically unlinked already.
            resume_this_greenlet = None
            if result is not self:  # pragma: no cover
                raise InvalidSwitchError('Invalid switch into %s.wait(): %r' %
                                         (
                                             self.__class__.__name__,
                                             result,
                                         ))
        finally:
            self._acquire_lock_for_switch_in()
            self.__unlink_all(resume_this_greenlet)
            self.__unlink_all(send)
            if watcher is not None:
                watcher.stop()
                watcher.close()