From 08884a67ddbbf3c296d8bd6ecb60ed1ec4beec6d Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Wed, 20 Sep 2017 18:42:13 +0200 Subject: [PATCH 1/3] bpo-31516: current_thread() should not return a dummy thread at shutdown --- Lib/test/test_threading.py | 29 +++++++++++++++++++++++++++++ Lib/threading.py | 3 +-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index f7c3680bda379b5..a042e4328695ee2 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -547,6 +547,35 @@ def f(): self.assertEqual(err, b"") self.assertEqual(data, "Thread-1\nTrue\nTrue\n") + def test_main_thread_during_shutdown(self): + # bpo-31516: current_thread() should still point to the main thread + # at shutdown + code = """if 1: + import gc, threading + + main_thread = threading.current_thread() + assert main_thread is threading.main_thread() + + class RefCycle: + def __init__(self): + self.cycle = self + + def __del__(self): + print("GC:", + threading.current_thread() is main_thread, + threading.main_thread() is main_thread, + threading.enumerate() == [main_thread]) + + RefCycle() + gc.collect() + x = RefCycle() + """ + _, out, err = assert_python_ok("-c", code) + data = out.decode() + self.assertEqual(err, b"") + self.assertEqual(data.splitlines(), + ["GC: True True True"] * 2) + def test_tstate_lock(self): # Test an implementation detail of Thread objects. started = _thread.allocate_lock() diff --git a/Lib/threading.py b/Lib/threading.py index e4bf974495b3926..418116faceb755b 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -1158,8 +1158,8 @@ def run(self): self.function(*self.args, **self.kwargs) self.finished.set() + # Special thread class to represent the main thread -# This is garbage collected through an exit handler class _MainThread(Thread): @@ -1272,7 +1272,6 @@ def _shutdown(): while t: t.join() t = _pickSomeNonDaemonThread() - _main_thread._delete() def _pickSomeNonDaemonThread(): for t in enumerate(): From d99f09f87874f14d90e8680726e876f9a7c3867e Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Wed, 20 Sep 2017 18:43:03 +0200 Subject: [PATCH 2/3] Add blurb --- .../NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst diff --git a/Misc/NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst b/Misc/NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst new file mode 100644 index 000000000000000..af48d159fef43cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-09-20-18-43-01.bpo-31516.23Yuq3.rst @@ -0,0 +1 @@ +``threading.current_thread()`` should not return a dummy thread at shutdown. From 63074a1fd9a2a042acbb42384fac5a49aa27ff3f Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Wed, 20 Sep 2017 20:14:59 +0200 Subject: [PATCH 3/3] Add comments --- Lib/test/test_threading.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index a042e4328695ee2..6e1ae06f7927e4f 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -554,7 +554,7 @@ def test_main_thread_during_shutdown(self): import gc, threading main_thread = threading.current_thread() - assert main_thread is threading.main_thread() + assert main_thread is threading.main_thread() # sanity check class RefCycle: def __init__(self): @@ -567,7 +567,7 @@ def __del__(self): threading.enumerate() == [main_thread]) RefCycle() - gc.collect() + gc.collect() # sanity check x = RefCycle() """ _, out, err = assert_python_ok("-c", code)