commit c4454e05284d36fb6ecafc9c2f33c7b0a9ffab43
Author: Damian Johnson <atagar(a)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()