summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2009-10-30 17:07:08 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2009-10-30 17:07:08 (GMT)
commit59c44f36e0a575671c0e8dab6a9de88666e481b0 (patch)
treed56d849af56fbc8af46e39c316cbfb1bb86cce36 /Lib/test
parent93c21714946d5fa287bb4aa1d9acb46d55f0b742 (diff)
downloadcpython-59c44f36e0a575671c0e8dab6a9de88666e481b0.zip
cpython-59c44f36e0a575671c0e8dab6a9de88666e481b0.tar.gz
cpython-59c44f36e0a575671c0e8dab6a9de88666e481b0.tar.bz2
Issue #7222: Make thread "reaping" more reliable so that reference
leak-chasing test runs give sensible results. The previous method of reaping threads could return successfully while some Thread objects were still referenced. This also introduces a new private function: :func:hread._count().
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_support.py29
-rw-r--r--Lib/test/test_thread.py27
2 files changed, 44 insertions, 12 deletions
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
index bfa3c45..fa46be2 100644
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -952,24 +952,29 @@ def run_doctest(module, verbosity=None):
#=======================================================================
# Threading support to prevent reporting refleaks when running regrtest.py -R
+# NOTE: we use thread._count() rather than threading.enumerate() (or the
+# moral equivalent thereof) because a threading.Thread object is still alive
+# until its __bootstrap() method has returned, even after it has been
+# unregistered from the threading module.
+# thread._count(), on the other hand, only gets decremented *after* the
+# __bootstrap() method has returned, which gives us reliable reference counts
+# at the end of a test run.
+
def threading_setup():
- import threading
- return len(threading._active), len(threading._limbo)
+ import thread
+ return thread._count(),
-def threading_cleanup(num_active, num_limbo):
- import threading
+def threading_cleanup(nb_threads):
+ import thread
import time
_MAX_COUNT = 10
- count = 0
- while len(threading._active) != num_active and count < _MAX_COUNT:
- count += 1
- time.sleep(0.1)
-
- count = 0
- while len(threading._limbo) != num_limbo and count < _MAX_COUNT:
- count += 1
+ for count in range(_MAX_COUNT):
+ n = thread._count()
+ if n == nb_threads:
+ break
time.sleep(0.1)
+ # XXX print a warning in case of failure?
def reap_threads(func):
@functools.wraps(func)
diff --git a/Lib/test/test_thread.py b/Lib/test/test_thread.py
index 66ad22f..4945047 100644
--- a/Lib/test/test_thread.py
+++ b/Lib/test/test_thread.py
@@ -4,6 +4,7 @@ import random
from test import test_support
import thread
import time
+import weakref
NUMTASKS = 10
@@ -101,6 +102,32 @@ class ThreadRunningTests(BasicThreadTest):
thread.stack_size(0)
+ def test__count(self):
+ # Test the _count() function.
+ orig = thread._count()
+ mut = thread.allocate_lock()
+ mut.acquire()
+ started = []
+ def task():
+ started.append(None)
+ mut.acquire()
+ mut.release()
+ thread.start_new_thread(task, ())
+ while not started:
+ time.sleep(0.01)
+ self.assertEquals(thread._count(), orig + 1)
+ # Allow the task to finish.
+ mut.release()
+ # The only reliable way to be sure that the thread ended from the
+ # interpreter's point of view is to wait for the function object to be
+ # destroyed.
+ done = []
+ wr = weakref.ref(task, lambda _: done.append(None))
+ del task
+ while not done:
+ time.sleep(0.01)
+ self.assertEquals(thread._count(), orig)
+
class Barrier:
def __init__(self, num_threads):