[tor-commits] [arm/master] fix: Stacktrace from unjoined thread at shutdown

atagar at torproject.org atagar at torproject.org
Thu Apr 28 05:02:18 UTC 2011


commit c4454e05284d36fb6ecafc9c2f33c7b0a9ffab43
Author: Damian Johnson <atagar at torproject.org>
Date:   Wed Apr 27 21:46:21 2011 -0700

    fix: Stacktrace from unjoined thread at shutdown
    
    There's a rare (but repeated) stack trace due to an unjoined thread at
    shutdown:
    Exception in thread Thread-3 (most likely raised during interpreter shutdown):
    Traceback (most recent call last):
      File "/usr/lib/python2.6/threading.py", line 525, in __bootstrap_inner
      File "/home/atagar/Desktop/arm/src/util/sysTools.py", line 542, in run
      File "/usr/lib/python2.6/threading.py", line 135, in release
    <type 'exceptions.TypeError'>: 'NoneType' object is not callable
    
    This isn't harmful, but it is annoying. This change is attempting to be extra
    careful that all resourceTracker threads have been joined, and that the
    controller is stopped beforehand (preventing stray BW events from triggering
    additional queries).
    
    The stacktrace _seems_ to be more commonly caused by long-running arm
    processes, but I don't have a reliable repro case.
---
 src/cli/controller.py             |   13 ++++++-------
 src/cli/graphing/resourceStats.py |    4 ++--
 src/util/sysTools.py              |   21 ++++-----------------
 3 files changed, 12 insertions(+), 26 deletions(-)

diff --git a/src/cli/controller.py b/src/cli/controller.py
index 22d1772..8543ccb 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -825,20 +825,19 @@ def drawTorMonitor(stdscr, startTime, loggedEvents, isBlindMode):
         panels["conn"].join()
         panels["log"].join()
         
-        # joins on utility daemon threads - this might take a moment since
-        # the internal threadpools being joined might be sleeping
         conn = torTools.getConn()
-        myPid = conn.getMyPid()
+        conn.close() # joins on TorCtl event thread
         
-        resourceTracker = sysTools.getResourceTracker(myPid) if (myPid and sysTools.isTrackerAlive(myPid)) else None
+        # joins on utility daemon threads - this might take a moment since
+        # the internal threadpools being joined might be sleeping
+        resourceTrackers = sysTools.RESOURCE_TRACKERS.values()
         resolver = connections.getResolver("tor") if connections.isResolverAlive("tor") else None
-        if resourceTracker: resourceTracker.stop()
+        for tracker in resourceTrackers: tracker.stop()
         if resolver: resolver.stop()  # sets halt flag (returning immediately)
         hostnames.stop()              # halts and joins on hostname worker thread pool
-        if resourceTracker: resourceTracker.join()
+        for tracker in resourceTrackers: tracker.join()
         if resolver: resolver.join()  # joins on halted resolver
         
-        conn.close() # joins on TorCtl event thread
         break
     elif key == curses.KEY_LEFT or key == curses.KEY_RIGHT:
       # switch page
diff --git a/src/cli/graphing/resourceStats.py b/src/cli/graphing/resourceStats.py
index f26d5c1..a9a8aee 100644
--- a/src/cli/graphing/resourceStats.py
+++ b/src/cli/graphing/resourceStats.py
@@ -36,9 +36,9 @@ class ResourceStats(graphPanel.GraphStats):
     
     primary, secondary = 0, 0
     if self.queryPid:
-      resourceTracker = sysTools.getResourceTracker(self.queryPid)
+      resourceTracker = sysTools.getResourceTracker(self.queryPid, True)
       
-      if not resourceTracker.lastQueryFailed():
+      if resourceTracker and not resourceTracker.lastQueryFailed():
         primary, _, secondary, _ = resourceTracker.getResourceUsage()
         primary *= 100        # decimal percentage to whole numbers
         secondary /= 1048576  # translate size to MB so axis labels are short
diff --git a/src/util/sysTools.py b/src/util/sysTools.py
index 8d95733..2775194 100644
--- a/src/util/sysTools.py
+++ b/src/util/sysTools.py
@@ -347,27 +347,13 @@ def call(command, cacheAge=0, suppressExc=False, quiet=True):
     
     return results
 
-def isTrackerAlive(pid):
-  """
-  Provides true if a running, singleton instance exists for the given pid,
-  false otherwise.
-  
-  Arguments:
-    pid - pid of the process being tracked
-  """
-  
-  if pid in RESOURCE_TRACKERS:
-    if RESOURCE_TRACKERS[pid].isAlive(): return True
-    else: del RESOURCE_TRACKERS[pid]
-  
-  return False
-
-def getResourceTracker(pid):
+def getResourceTracker(pid, noSpawn = False):
   """
   Provides a running singleton ResourceTracker instance for the given pid.
   
   Arguments:
-    pid - pid of the process being tracked
+    pid     - pid of the process being tracked
+    noSpawn - returns None rather than generating a singleton instance if True
   """
   
   if pid in RESOURCE_TRACKERS:
@@ -375,6 +361,7 @@ def getResourceTracker(pid):
     if tracker.isAlive(): return tracker
     else: del RESOURCE_TRACKERS[pid]
   
+  if noSpawn: return None
   tracker = ResourceTracker(pid, CONFIG["queries.resourceUsage.rate"])
   RESOURCE_TRACKERS[pid] = tracker
   tracker.start()



More information about the tor-commits mailing list