This subclass of Twisted’s selectreactor has methods to yield control of the reactor to its caller, and resume control later.

The guts of mainLoop have been moved to a generator method, and mainLoop instantiates the generator and calls .next() on it.

There are new methods for new functionality.

.release() causes the mainLoop to yield at the end of its current iteration.

.resume() transfers control back into the reactor. A .resume call is like .run, in that it does not yield control until the next .release or .stop.

.isRunning() tells you whether the reactor is running.



from twisted.python import log, failure, util
from twisted.internet.selectreactor import SelectReactor

class PausingReactor(SelectReactor):
    """Implement selectreactor that can be exited and resumed. """

    def __init__(self, *args):
        SelectReactor.__init__(self, *args)
        self._releaseRequested = False
        self._mainLoopGen = None

    def _mainLoopGenerater(self):
        """Generater that acts as mainLoop, but yields when
        requested.
        """
        while self.running:
            try:
                while self.running:
                    # Advance simulation time in delayed event
                    # processors.
                    self.runUntilCurrent()
                    t2 = self.timeout()
                    t = self.running and t2
                    self.doIteration(t)

                    if self._releaseRequested:
                        self._releaseRequested = False
                        yield None
            except:
                log.msg("Unexpected error in main loop.")
                log.deferr()
            else:
                log.msg('Main loop terminated.')

    def mainLoop(self):
        """Setup mainLoop generater, and initiate looping. """
        self._mainLoopGen = self._mainLoopGenerater()
        self.resume()

    def resume(self):
        """Resume mainLoop looping after interruption. """
        try:
            self._mainLoopGen.next()
        except StopIteration:
            pass

    def release(self):
        """Request main loop pause and reacter yield to caller. """
        self._releaseRequested = True

    def isRunning(self):
        """Is reactor running? """
        return self.running

def install():
    """Configure the twisted mainloop to be run using the pausingreactor.
    """
    reactor = PausingReactor()
    from twisted.internet.main import installReactor
    installReactor(reactor)

__all__ = ['install']

To use the module,
import pausingreactor; pausingreactor.install()

The pausingreactor module, and a couple of files to test it, are linked. The stresstest.py sends increasing long strings to an echo type server ‘uppercaser_ns.py’, reads them back and checks them for intactness. It also pauses a couple times per second for a fraction of a second.

pausingreactor.py

stresstest.py

uppercaser_ns.py

Enjoy.

Advertisements