Пример #1
0
    def run_callback(self, func, *args):
        # If we happen to already be running callbacks (inside
        # _run_callbacks), this could happen almost immediately,
        # without the loop cycling.
        cb = callback(func, args)
        self._callbacks.append(cb)
        self._setup_for_run_callback()

        return cb
Пример #2
0
 def callback(self, priority=None):
     return callback(self, priority)
Пример #3
0
    def _run_callbacks(self):  # pylint:disable=too-many-branches
        # When we're running callbacks, its safe for timers to
        # update the notion of the current time (because if we're here,
        # we're not running in a timer callback that may let other timers
        # run; this is mostly an issue for libuv).

        # That's actually a bit of a lie: on libev, self._timer0 really is
        # a timer, and so sometimes this is running in a timer callback, not
        # a prepare callback. But that's OK, libev doesn't suffer from cascading
        # timer expiration and its safe to update the loop time at any
        # moment there.
        self.starting_timer_may_update_loop_time = True
        try:
            count = CALLBACK_CHECK_COUNT
            now = self.now()
            expiration = now + getswitchinterval()
            self._stop_callback_timer()
            while self._callbacks:
                cb = self._callbacks.popleft()
                count -= 1
                self.unref()  # XXX: libuv doesn't have a global ref count!
                callback = cb.callback
                cb.callback = None
                args = cb.args
                if callback is None or args is None:
                    # it's been stopped
                    continue

                try:
                    callback(*args)
                except:  # pylint:disable=bare-except
                    # If we allow an exception to escape this method (while we are running the ev callback),
                    # then CFFI will print the error and libev will continue executing.
                    # There are two problems with this. The first is that the code after
                    # the loop won't run. The second is that any remaining callbacks scheduled
                    # for this loop iteration will be silently dropped; they won't run, but they'll
                    # also not be *stopped* (which is not a huge deal unless you're looking for
                    # consistency or checking the boolean/pending status; the loop doesn't keep
                    # a reference to them like it does to watchers...*UNLESS* the callback itself had
                    # a reference to a watcher; then I don't know what would happen, it depends on
                    # the state of the watcher---a leak or crash is not totally inconceivable).
                    # The Cython implementation in core.ppyx uses gevent_call from callbacks.c
                    # to run the callback, which uses gevent_handle_error to handle any errors the
                    # Python callback raises...it unconditionally simply prints any error raised
                    # by loop.handle_error and clears it, so callback handling continues.
                    # We take a similar approach (but are extra careful about printing)
                    try:
                        self.handle_error(cb, *sys.exc_info())
                    except:  # pylint:disable=bare-except
                        try:
                            print("Exception while handling another error",
                                  file=sys.stderr)
                            traceback.print_exc()
                        except:  # pylint:disable=bare-except
                            pass  # Nothing we can do here
                finally:
                    # NOTE: this must be reset here, because cb.args is used as a flag in
                    # the callback class so that bool(cb) of a callback that has been run
                    # becomes False
                    cb.args = None

                # We've finished running one group of callbacks
                # but we may have more, so before looping check our
                # switch interval.
                if count == 0 and self._callbacks:
                    count = CALLBACK_CHECK_COUNT
                    self.update_now()
                    if self.now() >= expiration:
                        now = 0
                        break

            # Update the time before we start going again, if we didn't
            # just do so.
            if now != 0:
                self.update_now()

            if self._callbacks:
                self._start_callback_timer()
        finally:
            self.starting_timer_may_update_loop_time = False
Пример #4
0
 def callback(self, priority=None):
     return callback(self, priority)
Пример #5
0
    def _run_callbacks(self): # pylint:disable=too-many-branches
        # When we're running callbacks, its safe for timers to
        # update the notion of the current time (because if we're here,
        # we're not running in a timer callback that may let other timers
        # run; this is mostly an issue for libuv).

        # That's actually a bit of a lie: on libev, self._timer0 really is
        # a timer, and so sometimes this is running in a timer callback, not
        # a prepare callback. But that's OK, libev doesn't suffer from cascading
        # timer expiration and its safe to update the loop time at any
        # moment there.
        self.starting_timer_may_update_loop_time = True
        try:
            count = CALLBACK_CHECK_COUNT
            now = self.now()
            expiration = now + getswitchinterval()
            self._stop_callback_timer()
            while self._callbacks:
                cb = self._callbacks.popleft() # pylint:disable=assignment-from-no-return
                count -= 1
                self.unref() # XXX: libuv doesn't have a global ref count!
                callback = cb.callback
                cb.callback = None
                args = cb.args
                if callback is None or args is None:
                    # it's been stopped
                    continue

                try:
                    callback(*args)
                except: # pylint:disable=bare-except
                    # If we allow an exception to escape this method (while we are running the ev callback),
                    # then CFFI will print the error and libev will continue executing.
                    # There are two problems with this. The first is that the code after
                    # the loop won't run. The second is that any remaining callbacks scheduled
                    # for this loop iteration will be silently dropped; they won't run, but they'll
                    # also not be *stopped* (which is not a huge deal unless you're looking for
                    # consistency or checking the boolean/pending status; the loop doesn't keep
                    # a reference to them like it does to watchers...*UNLESS* the callback itself had
                    # a reference to a watcher; then I don't know what would happen, it depends on
                    # the state of the watcher---a leak or crash is not totally inconceivable).
                    # The Cython implementation in core.ppyx uses gevent_call from callbacks.c
                    # to run the callback, which uses gevent_handle_error to handle any errors the
                    # Python callback raises...it unconditionally simply prints any error raised
                    # by loop.handle_error and clears it, so callback handling continues.
                    # We take a similar approach (but are extra careful about printing)
                    try:
                        self.handle_error(cb, *sys.exc_info())
                    except: # pylint:disable=bare-except
                        try:
                            print("Exception while handling another error", file=sys.stderr)
                            traceback.print_exc()
                        except: # pylint:disable=bare-except
                            pass # Nothing we can do here
                finally:
                    # NOTE: this must be reset here, because cb.args is used as a flag in
                    # the callback class so that bool(cb) of a callback that has been run
                    # becomes False
                    cb.args = None

                # We've finished running one group of callbacks
                # but we may have more, so before looping check our
                # switch interval.
                if count == 0 and self._callbacks:
                    count = CALLBACK_CHECK_COUNT
                    self.update_now()
                    if self.now() >= expiration:
                        now = 0
                        break

            # Update the time before we start going again, if we didn't
            # just do so.
            if now != 0:
                self.update_now()

            if self._callbacks:
                self._start_callback_timer()
        finally:
            self.starting_timer_may_update_loop_time = False
Пример #6
0
    def run_callback(self, func, *args):
        cb = callback(func, args)
        self._callbacks.append(cb)
        self._setup_for_run_callback()

        return cb