Esempio n. 1
0
def loop(condition, timeout=None):
    """
    Executes the main loop until condition is met.

    This function may be called recursively, however two loops may not
    run in parallel threads.

    :param condition: a callable or object that is evaluated after each step
                      of the loop.  If it evaluates False, the loop
                      terminates.  (If condition is therefore ``True``, the
                      loop will run forever.)
    :param timeout: number of seconds after which the loop will terminate
                    (regardless of the condition).
    """
    _loop_lock.acquire()
    if is_running() and not is_mainthread():
        # race condition. Two threads started a mainloop and the other
        # one is executed right now. Raise a RuntimeError
        _loop_lock.release()
        raise RuntimeError('loop running in a different thread')

    initial_mainloop = False
    if not is_running():
        # no mainloop is running, set this thread as mainloop and
        # set the internal running state.
        initial_mainloop = True
        set_as_mainthread()
        _set_running(True)
    # ok, that was the critical part
    _loop_lock.release()

    if not callable(condition):
        condition = lambda: condition

    abort = []
    if timeout is not None:
        # timeout handling to stop the mainloop after the given timeout
        # even when the condition is still True.
        sec = timeout
        timeout = OneShotTimer(lambda: abort.append(True))
        timeout.start(sec)

    try:
        while condition() and not abort:
            try:
                notifier.step()
                signals['step'].emit()
            except BaseException, e:
                if signals['exception'].emit(*sys.exc_info()) != False:
                    # Either there are no global exception handlers, or none of
                    # them explicitly returned False to abort mainloop
                    # termination.  So abort the main loop.
                    type, value, tb = sys.exc_info()
                    raise type, value, tb
    finally:
        # make sure we set mainloop status
        if timeout is not None:
            timeout.stop()
        if initial_mainloop:
            _set_running(False)
Esempio n. 2
0
 def handle(self):
     """
     Callback from the real mainloop.
     """
     try:
         try:
             notifier.step(sleep = False)
         except (KeyboardInterrupt, SystemExit):
             set_mainloop_running(False)
             notifier.shutdown()
     finally:
         self._lock.release()
Esempio n. 3
0
def step(*args, **kwargs):
    """
    Performs a single iteration of the main loop.

    This function should almost certainly never be called directly.  Use it
    at your own peril.
    """
    if not is_mainthread():
        # If step is being called from a thread, wake up the mainthread
        # instead of allowing the thread into notifier.step.
        wakeup()
        # Sleep for epsilon to prevent busy loops.
        time.sleep(0.001)
        return
    notifier.step(*args, **kwargs)
    signals['step'].emit()
Esempio n. 4
0
 def run(self):
     """
     Thread part running the blocking, simulating loop.
     """
     set_mainloop_running(True)
     try:
         while True:
             self.sleeping = True
             notifier.step(simulate = True)
             self.sleeping = False
             if not main.is_running():
                 break
             self._call_mainloop(self.handle)
             self._lock.acquire()
             if not main.is_running():
                 break
     except (KeyboardInterrupt, SystemExit):
         pass
     except Exception, e:
         log.exception('loop')