Index: src/mlx/fsuipc.py
===================================================================
--- src/mlx/fsuipc.py	(revision 530)
+++ src/mlx/fsuipc.py	(revision 535)
@@ -4,4 +4,5 @@
 import util
 import acft
+from watchdog import Watchdog
 
 import threading
@@ -244,4 +245,6 @@
         self._periodicRequests = []
 
+        self._watchdogClient = Watchdog.get().addClient(2.0, "fsuipc.Handler")
+
         self.daemon = True
 
@@ -441,4 +444,5 @@
         needReconnect = False
         try:
+            self._watchdogClient.set()
             try:
                 if not request.process(time):
@@ -459,4 +463,5 @@
                 return 0
         finally:
+            self._watchdogClient.clear()
             self._requestCondition.acquire()
 
Index: src/mlx/mlx.py
===================================================================
--- src/mlx/mlx.py	(revision 402)
+++ src/mlx/mlx.py	(revision 535)
@@ -5,4 +5,5 @@
 from util import secondaryInstallation
 from const import VERSION
+from watchdog import Watchdog
 
 import os
@@ -90,4 +91,6 @@
 
     try:
+        Watchdog().start()
+
         gui.build(programDirectory)
 
Index: src/mlx/watchdog.py
===================================================================
--- src/mlx/watchdog.py	(revision 535)
+++ src/mlx/watchdog.py	(revision 535)
@@ -0,0 +1,136 @@
+# Watchdog
+
+#-----------------------------------------------------------------------------
+
+from threading import Thread, Lock
+
+import time
+
+#-----------------------------------------------------------------------------
+
+## @package mlx.watchdog
+#
+# Watchdog module. It implements a thread which wakes up regularly and checks
+# that none of its clients is left in a state for too long a time. If so, that
+# fact is logged.
+
+#-----------------------------------------------------------------------------
+
+class _ClientState(object):
+    """A client state.
+
+    It can be set or cleared. If set, there is a timeout associated with it. If
+    the timeout is over, the client state is logged. If it becomes clear later,
+    that fact is logged too."""
+    def __init__(self, timeout, name):
+        """Construct the client state with the given timeout and log text."""
+
+        self._lock = Lock()
+
+        self._timeout = timeout
+        self._name = name
+        self._nextTimeout = None
+        self._timedout = False
+
+    def set(self):
+        """Put the client into the set state."""
+        with self._lock:
+            if self._nextTimeout is None:
+                self._nextTimeout = time.time() + self._timeout
+
+    def clear(self):
+        """Put the client into the cleared state."""
+        with self._lock:
+            self._nextTimeout = None
+
+    def _check(self, t):
+        """Check the client state.
+
+        If it has timed out, and it has not been logged yet, it is logged. If
+        it is cleared, but had a timeout earlier, that fact is also logged."""
+        logTimeout = False
+        logCleared = False
+        with self._lock:
+            if self._nextTimeout is None:
+                logCleared = self._timedout
+                self._timedout = False
+            elif t>=self._nextTimeout:
+                logTimeout = not self._timedout
+                self._timedout = True
+
+        if logTimeout:
+            print "Watchdog client %s has timed out!" % (self._name)
+        elif logCleared:
+            print "Watchdog client %s has been cleared." % (self._name)
+
+#-----------------------------------------------------------------------------
+
+class Watchdog(Thread):
+    """The watchdog thread."""
+    _instance = None
+
+    WAKEUP_INTERVAL = 1.0
+
+    LOG_INTERVAL = 60.0
+
+    @staticmethod
+    def get():
+        """Get the only instance of the watchdog."""
+        return Watchdog._instance
+
+    def __init__(self):
+        """Construct the watchdog."""
+        assert self._instance is None
+
+        super(Watchdog, self).__init__()
+        self.daemon = True
+
+        self._lock = Lock()
+        self._clients = []
+
+        Watchdog._instance = self
+
+    def addClient(self, timeout, name):
+        """Add a client with the given timeout and name.
+
+        The new client is returned."""
+        client = _ClientState(timeout, name)
+        with self._lock:
+            self._clients.append(client)
+        return client
+
+    def run(self):
+        """Perform the client checks, then wait for WAKEUP_INTERVAL.
+
+        If LOG_INTERVAL elapses, put an entry in the debug log to confirm that
+        the watchdog still works."""
+
+        nextLogTime = time.time()
+        nextWakeupTime = nextLogTime + self.WAKEUP_INTERVAL
+
+        while True:
+            t = time.time()
+            while t>=nextWakeupTime:
+                nextWakeupTime += self.WAKEUP_INTERVAL
+
+            if t>=nextLogTime:
+                print "Watchdog.run: running"
+                while t>=nextLogTime:
+                    nextLogTime += self.LOG_INTERVAL
+
+            self._checkClients(t)
+
+            t = time.time()
+            if t<nextWakeupTime:
+                time.sleep(nextWakeupTime - t)
+
+    def _checkClients(self, t):
+        """Check the clients."""
+        with self._lock:
+            clients = self._clients[:]
+
+        for client in clients:
+            client._check(t)
+
+#-----------------------------------------------------------------------------
+#-----------------------------------------------------------------------------
Index: src/mlx/xplane.py
===================================================================
--- src/mlx/xplane.py	(revision 505)
+++ src/mlx/xplane.py	(revision 535)
@@ -3,4 +3,5 @@
 import const
 import util
+from watchdog import Watchdog
 
 import threading
@@ -341,4 +342,6 @@
         self._periodicRequests = []
 
+        self._watchdogClient = Watchdog.get().addClient(2.0, "xplane.Handler")
+
         self.daemon = True
 
@@ -571,4 +574,5 @@
         needReconnect = False
         try:
+            self._watchdogClient.set()
             try:
                 if not request.process(time):
@@ -589,4 +593,5 @@
                 return 0
         finally:
+            self._watchdogClient.clear()
             self._requestCondition.acquire()
 
