コード例 #1
0
    def test_timer_collision(self):
        # simple test demonstrating #466
        # same timeout, comparison will defer to the Timer object itself
        t1 = Timer(0, lambda: None)
        t2 = Timer(0, lambda: None)
        t2.end = t1.end

        tm = TimerManager()
        tm.add_timer(t1)
        tm.add_timer(t2)
        # Prior to #466: "TypeError: unorderable types: Timer() < Timer()"
        tm.service_timeouts()
コード例 #2
0
class TwistedLoop(object):

    _lock = None
    _thread = None
    _timeout_task = None
    _timeout = None

    def __init__(self):
        self._lock = Lock()
        self._timers = TimerManager()

    def maybe_start(self):
        with self._lock:
            if not reactor.running:
                self._thread = Thread(target=reactor.run,
                                      name="dse_driver_event_loop",
                                      kwargs={'installSignalHandlers': False})
                self._thread.daemon = True
                self._thread.start()
                atexit.register(partial(_cleanup, weakref.ref(self)))

    def _cleanup(self):
        if self._thread:
            reactor.callFromThread(reactor.stop)
            self._thread.join(timeout=1.0)
            if self._thread.is_alive():
                log.warning("Event loop thread could not be joined, so "
                            "shutdown may not be clean. Please call "
                            "Cluster.shutdown() to avoid this.")
            log.debug("Event loop thread was joined")

    def add_timer(self, timer):
        self._timers.add_timer(timer)
        # callFromThread to schedule from the loop thread, where
        # the timeout task can safely be modified
        reactor.callFromThread(self._schedule_timeout, timer.end)

    def _schedule_timeout(self, next_timeout):
        if next_timeout:
            delay = max(next_timeout - time.time(), 0)
            if self._timeout_task and self._timeout_task.active():
                if next_timeout < self._timeout:
                    self._timeout_task.reset(delay)
                    self._timeout = next_timeout
            else:
                self._timeout_task = reactor.callLater(delay,
                                                       self._on_loop_timer)
                self._timeout = next_timeout

    def _on_loop_timer(self):
        self._timers.service_timeouts()
        self._schedule_timeout(self._timers.next_timeout)
コード例 #3
0
class AsyncoreLoop(object):

    timer_resolution = 0.1  # used as the max interval to be in the io loop before returning to service timeouts

    _loop_dispatch_class = _AsyncorePipeDispatcher if os.name != 'nt' else _BusyWaitDispatcher

    def __init__(self):
        self._pid = os.getpid()
        self._loop_lock = Lock()
        self._started = False
        self._shutdown = False

        self._thread = None

        self._timers = TimerManager()

        try:
            dispatcher = self._loop_dispatch_class()
            dispatcher.validate()
            log.debug("Validated loop dispatch with %s", self._loop_dispatch_class)
        except Exception:
            log.exception("Failed validating loop dispatch with %s. Using busy wait execution instead.", self._loop_dispatch_class)
            dispatcher.close()
            dispatcher = _BusyWaitDispatcher()
        self._loop_dispatcher = dispatcher

        atexit.register(partial(_cleanup, weakref.ref(self)))

    def maybe_start(self):
        should_start = False
        did_acquire = False
        try:
            did_acquire = self._loop_lock.acquire(False)
            if did_acquire and not self._started:
                self._started = True
                should_start = True
        finally:
            if did_acquire:
                self._loop_lock.release()

        if should_start:
            self._thread = Thread(target=self._run_loop, name="dse_driver_event_loop")
            self._thread.daemon = True
            self._thread.start()

    def wake_loop(self):
        self._loop_dispatcher.notify_loop()

    def _run_loop(self):
        log.debug("Starting asyncore event loop")
        with self._loop_lock:
            while not self._shutdown:
                try:
                    self._loop_dispatcher.loop(self.timer_resolution)
                    self._timers.service_timeouts()
                except Exception:
                    log.debug("Asyncore event loop stopped unexepectedly", exc_info=True)
                    break
            self._started = False

        log.debug("Asyncore event loop ended")

    def add_timer(self, timer):
        self._timers.add_timer(timer)

    def _cleanup(self):
        self._shutdown = True
        if not self._thread:
            return

        log.debug("Waiting for event loop thread to join...")
        self._thread.join(timeout=1.0)
        if self._thread.is_alive():
            log.warning(
                "Event loop thread could not be joined, so shutdown may not be clean. "
                "Please call Cluster.shutdown() to avoid this.")

        log.debug("Event loop thread was joined")
コード例 #4
0
class LibevLoop(object):

    def __init__(self):
        self._pid = os.getpid()
        self._loop = libev.Loop()
        self._notifier = libev.Async(self._loop)
        self._notifier.start()

        # prevent _notifier from keeping the loop from returning
        self._loop.unref()

        self._started = False
        self._shutdown = False
        self._lock = Lock()

        self._thread = None

        # set of all connections; only replaced with a new copy
        # while holding _conn_set_lock, never modified in place
        self._live_conns = set()
        # newly created connections that need their write/read watcher started
        self._new_conns = set()
        # recently closed connections that need their write/read watcher stopped
        self._closed_conns = set()
        self._conn_set_lock = Lock()

        self._preparer = libev.Prepare(self._loop, self._loop_will_run)
        # prevent _preparer from keeping the loop from returning
        self._loop.unref()
        self._preparer.start()

        self._timers = TimerManager()
        self._loop_timer = libev.Timer(self._loop, self._on_loop_timer)

        atexit.register(partial(_cleanup, weakref.ref(self)))

    def maybe_start(self):
        should_start = False
        with self._lock:
            if not self._started:
                log.debug("Starting libev event loop")
                self._started = True
                should_start = True

        if should_start:
            self._thread = Thread(target=self._run_loop, name="event_loop")
            self._thread.daemon = True
            self._thread.start()

        self._notifier.send()

    def _run_loop(self):
        while True:
            self._loop.start()
            # there are still active watchers, no deadlock
            with self._lock:
                if not self._shutdown and self._live_conns:
                    log.debug("Restarting event loop")
                    continue
                else:
                    # all Connections have been closed, no active watchers
                    log.debug("All Connections currently closed, event loop ended")
                    self._started = False
                    break

    def _cleanup(self):
        self._shutdown = True
        if not self._thread:
            return

        for conn in self._live_conns | self._new_conns | self._closed_conns:
            conn.close()
            map(lambda w: w.stop(), (w for w in (conn._write_watcher, conn._read_watcher) if w))

        self.notify()  # wake the timer watcher
        log.debug("Waiting for event loop thread to join...")
        self._thread.join(timeout=1.0)
        if self._thread.is_alive():
            log.warning(
                "Event loop thread could not be joined, so shutdown may not be clean. "
                "Please call Cluster.shutdown() to avoid this.")

        log.debug("Event loop thread was joined")

    def add_timer(self, timer):
        self._timers.add_timer(timer)
        self._notifier.send()  # wake up in case this timer is earlier

    def _update_timer(self):
        if not self._shutdown:
            next_end = self._timers.service_timeouts()
            if next_end:
                self._loop_timer.start(next_end - time.time())  # timer handles negative values
        else:
            self._loop_timer.stop()

    def _on_loop_timer(self):
        self._timers.service_timeouts()

    def notify(self):
        self._notifier.send()

    def connection_created(self, conn):
        with self._conn_set_lock:
            new_live_conns = self._live_conns.copy()
            new_live_conns.add(conn)
            self._live_conns = new_live_conns

            new_new_conns = self._new_conns.copy()
            new_new_conns.add(conn)
            self._new_conns = new_new_conns

    def connection_destroyed(self, conn):
        with self._conn_set_lock:
            new_live_conns = self._live_conns.copy()
            new_live_conns.discard(conn)
            self._live_conns = new_live_conns

            new_closed_conns = self._closed_conns.copy()
            new_closed_conns.add(conn)
            self._closed_conns = new_closed_conns

        self._notifier.send()

    def _loop_will_run(self, prepare):
        changed = False
        for conn in self._live_conns:
            if not conn.deque and conn._write_watcher_is_active:
                if conn._write_watcher:
                    conn._write_watcher.stop()
                conn._write_watcher_is_active = False
                changed = True
            elif conn.deque and not conn._write_watcher_is_active:
                conn._write_watcher.start()
                conn._write_watcher_is_active = True
                changed = True

        if self._new_conns:
            with self._conn_set_lock:
                to_start = self._new_conns
                self._new_conns = set()

            for conn in to_start:
                conn._read_watcher.start()

            changed = True

        if self._closed_conns:
            with self._conn_set_lock:
                to_stop = self._closed_conns
                self._closed_conns = set()

            for conn in to_stop:
                if conn._write_watcher:
                    conn._write_watcher.stop()
                    # clear reference cycles from IO callback
                    del conn._write_watcher
                if conn._read_watcher:
                    conn._read_watcher.stop()
                    # clear reference cycles from IO callback
                    del conn._read_watcher

            changed = True

        # TODO: update to do connection management, timer updates through dedicated async 'notifier' callbacks
        self._update_timer()

        if changed:
            self._notifier.send()
コード例 #5
0
class AsyncoreLoop(object):

    timer_resolution = 0.1  # used as the max interval to be in the io loop before returning to service timeouts

    _loop_dispatch_class = _AsyncorePipeDispatcher if os.name != 'nt' else _BusyWaitDispatcher

    def __init__(self):
        self._pid = os.getpid()
        self._loop_lock = Lock()
        self._started = False
        self._shutdown = False

        self._thread = None

        self._timers = TimerManager()

        try:
            dispatcher = self._loop_dispatch_class()
            dispatcher.validate()
            log.debug("Validated loop dispatch with %s",
                      self._loop_dispatch_class)
        except Exception:
            log.exception(
                "Failed validating loop dispatch with %s. Using busy wait execution instead.",
                self._loop_dispatch_class)
            dispatcher.close()
            dispatcher = _BusyWaitDispatcher()
        self._loop_dispatcher = dispatcher

    def maybe_start(self):
        should_start = False
        did_acquire = False
        try:
            did_acquire = self._loop_lock.acquire(False)
            if did_acquire and not self._started:
                self._started = True
                should_start = True
        finally:
            if did_acquire:
                self._loop_lock.release()

        if should_start:
            self._thread = Thread(target=self._run_loop,
                                  name="asyncore_dse_driver_event_loop")
            self._thread.daemon = True
            self._thread.start()

    def wake_loop(self):
        self._loop_dispatcher.notify_loop()

    def _run_loop(self):
        log.debug("Starting asyncore event loop")
        with self._loop_lock:
            while not self._shutdown:
                try:
                    self._loop_dispatcher.loop(self.timer_resolution)
                    self._timers.service_timeouts()
                except Exception:
                    log.debug("Asyncore event loop stopped unexepectedly",
                              exc_info=True)
                    break
            self._started = False

        log.debug("Asyncore event loop ended")

    def add_timer(self, timer):
        self._timers.add_timer(timer)

        # This function is called from a different thread than the event loop
        # thread, so for this call to be thread safe, we must wake up the loop
        # in case it's stuck at a select
        self.wake_loop()

    def _cleanup(self):
        global _dispatcher_map

        self._shutdown = True
        if not self._thread:
            return

        log.debug("Waiting for event loop thread to join...")
        self._thread.join(timeout=1.0)
        if self._thread.is_alive():
            log.warning(
                "Event loop thread could not be joined, so shutdown may not be clean. "
                "Please call Cluster.shutdown() to avoid this.")

        log.debug("Event loop thread was joined")

        # Ensure all connections are closed and in-flight requests cancelled
        for conn in tuple(_dispatcher_map.values()):
            if conn is not self._loop_dispatcher:
                conn.close()
        self._timers.service_timeouts()
        # Once all the connections are closed, close the dispatcher
        self._loop_dispatcher.close()

        log.debug("Dispatchers were closed")