summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_audit.py2
-rw-r--r--Lib/test/test_concurrent_futures/test_process_pool.py4
-rw-r--r--Lib/test/test_thread.py48
-rw-r--r--Lib/test/test_threading.py61
4 files changed, 52 insertions, 63 deletions
diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py
index cd0a4e2..c24c821 100644
--- a/Lib/test/test_audit.py
+++ b/Lib/test/test_audit.py
@@ -209,7 +209,7 @@ class AuditTest(unittest.TestCase):
expected = [
("_thread.start_new_thread", "(<test_func>, (), None)"),
("test.test_func", "()"),
- ("_thread.start_joinable_thread", "(<test_func>,)"),
+ ("_thread.start_joinable_thread", "(<test_func>, 1, None)"),
("test.test_func", "()"),
]
diff --git a/Lib/test/test_concurrent_futures/test_process_pool.py b/Lib/test/test_concurrent_futures/test_process_pool.py
index 7fc59a0..70444bb 100644
--- a/Lib/test/test_concurrent_futures/test_process_pool.py
+++ b/Lib/test/test_concurrent_futures/test_process_pool.py
@@ -201,13 +201,13 @@ class ProcessPoolExecutorTest(ExecutorTest):
# QueueFeederThread.
orig_start_new_thread = threading._start_joinable_thread
nthread = 0
- def mock_start_new_thread(func, *args):
+ def mock_start_new_thread(func, *args, **kwargs):
nonlocal nthread
if nthread >= 1:
raise RuntimeError("can't create new thread at "
"interpreter shutdown")
nthread += 1
- return orig_start_new_thread(func, *args)
+ return orig_start_new_thread(func, *args, **kwargs)
with support.swap_attr(threading, '_start_joinable_thread',
mock_start_new_thread):
diff --git a/Lib/test/test_thread.py b/Lib/test/test_thread.py
index 8323523..d94e042 100644
--- a/Lib/test/test_thread.py
+++ b/Lib/test/test_thread.py
@@ -289,6 +289,54 @@ class ThreadRunningTests(BasicThreadTest):
with self.assertRaisesRegex(RuntimeError, "Cannot join current thread"):
raise error
+ def test_join_with_timeout(self):
+ lock = thread.allocate_lock()
+ lock.acquire()
+
+ def thr():
+ lock.acquire()
+
+ with threading_helper.wait_threads_exit():
+ handle = thread.start_joinable_thread(thr)
+ handle.join(0.1)
+ self.assertFalse(handle.is_done())
+ lock.release()
+ handle.join()
+ self.assertTrue(handle.is_done())
+
+ def test_join_unstarted(self):
+ handle = thread._ThreadHandle()
+ with self.assertRaisesRegex(RuntimeError, "thread not started"):
+ handle.join()
+
+ def test_set_done_unstarted(self):
+ handle = thread._ThreadHandle()
+ with self.assertRaisesRegex(RuntimeError, "thread not started"):
+ handle._set_done()
+
+ def test_start_duplicate_handle(self):
+ lock = thread.allocate_lock()
+ lock.acquire()
+
+ def func():
+ lock.acquire()
+
+ handle = thread._ThreadHandle()
+ with threading_helper.wait_threads_exit():
+ thread.start_joinable_thread(func, handle=handle)
+ with self.assertRaisesRegex(RuntimeError, "thread already started"):
+ thread.start_joinable_thread(func, handle=handle)
+ lock.release()
+ handle.join()
+
+ def test_start_with_none_handle(self):
+ def func():
+ pass
+
+ with threading_helper.wait_threads_exit():
+ handle = thread.start_joinable_thread(func, handle=None)
+ handle.join()
+
class Barrier:
def __init__(self, num_threads):
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index 8868666..f1dc129 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -408,7 +408,7 @@ class ThreadTests(BaseTestCase):
def test_limbo_cleanup(self):
# Issue 7481: Failure to start thread should cleanup the limbo map.
- def fail_new_thread(*args):
+ def fail_new_thread(*args, **kwargs):
raise threading.ThreadError()
_start_joinable_thread = threading._start_joinable_thread
threading._start_joinable_thread = fail_new_thread
@@ -912,41 +912,6 @@ class ThreadTests(BaseTestCase):
rc, out, err = assert_python_ok("-c", code)
self.assertEqual(err, b"")
- def test_tstate_lock(self):
- # Test an implementation detail of Thread objects.
- started = _thread.allocate_lock()
- finish = _thread.allocate_lock()
- started.acquire()
- finish.acquire()
- def f():
- started.release()
- finish.acquire()
- time.sleep(0.01)
- # The tstate lock is None until the thread is started
- t = threading.Thread(target=f)
- self.assertIs(t._tstate_lock, None)
- t.start()
- started.acquire()
- self.assertTrue(t.is_alive())
- # The tstate lock can't be acquired when the thread is running
- # (or suspended).
- tstate_lock = t._tstate_lock
- self.assertFalse(tstate_lock.acquire(timeout=0), False)
- finish.release()
- # When the thread ends, the state_lock can be successfully
- # acquired.
- self.assertTrue(tstate_lock.acquire(timeout=support.SHORT_TIMEOUT), False)
- # But is_alive() is still True: we hold _tstate_lock now, which
- # prevents is_alive() from knowing the thread's end-of-life C code
- # is done.
- self.assertTrue(t.is_alive())
- # Let is_alive() find out the C code is done.
- tstate_lock.release()
- self.assertFalse(t.is_alive())
- # And verify the thread disposed of _tstate_lock.
- self.assertIsNone(t._tstate_lock)
- t.join()
-
def test_repr_stopped(self):
# Verify that "stopped" shows up in repr(Thread) appropriately.
started = _thread.allocate_lock()
@@ -1112,30 +1077,6 @@ class ThreadTests(BaseTestCase):
self.assertEqual(threading.getprofile(), old_profile)
self.assertEqual(sys.getprofile(), old_profile)
- @cpython_only
- def test_shutdown_locks(self):
- for daemon in (False, True):
- with self.subTest(daemon=daemon):
- event = threading.Event()
- thread = threading.Thread(target=event.wait, daemon=daemon)
-
- # Thread.start() must add lock to _shutdown_locks,
- # but only for non-daemon thread
- thread.start()
- tstate_lock = thread._tstate_lock
- if not daemon:
- self.assertIn(tstate_lock, threading._shutdown_locks)
- else:
- self.assertNotIn(tstate_lock, threading._shutdown_locks)
-
- # unblock the thread and join it
- event.set()
- thread.join()
-
- # Thread._stop() must remove tstate_lock from _shutdown_locks.
- # Daemon threads must never add it to _shutdown_locks.
- self.assertNotIn(tstate_lock, threading._shutdown_locks)
-
def test_locals_at_exit(self):
# bpo-19466: thread locals must not be deleted before destructors
# are called