diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2021-09-27 21:39:35 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-27 21:39:35 (GMT) |
commit | 38c67738c64304928c68d5c2bd78bbb01d979b94 (patch) | |
tree | 0a1357604728fce7834e35e1fa0a495db87d59b9 | |
parent | c7fdd6879b5c8447ee65b1bec95a1db43837a7a5 (diff) | |
download | cpython-38c67738c64304928c68d5c2bd78bbb01d979b94.zip cpython-38c67738c64304928c68d5c2bd78bbb01d979b94.tar.gz cpython-38c67738c64304928c68d5c2bd78bbb01d979b94.tar.bz2 |
bpo-1596321: Fix threading._shutdown() for the main thread (GH-28549)
Fix the threading._shutdown() function when the threading module was
imported first from a thread different than the main thread: no
longer log an error at Python exit.
(cherry picked from commit 95d31370829b7d729667588e0a9943217401ea5b)
Co-authored-by: Victor Stinner <vstinner@python.org>
-rw-r--r-- | Lib/test/test_threading.py | 33 | ||||
-rw-r--r-- | Lib/threading.py | 25 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2021-09-24-17-20-23.bpo-1596321.3nhPUk.rst | 3 |
3 files changed, 53 insertions, 8 deletions
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index c51de6f..c54806e 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -928,6 +928,39 @@ class ThreadTests(BaseTestCase): b'is deprecated and will be removed in Python 3.12') self.assertIn(msg, err) + def test_import_from_another_thread(self): + # bpo-1596321: If the threading module is first import from a thread + # different than the main thread, threading._shutdown() must handle + # this case without logging an error at Python exit. + code = textwrap.dedent(''' + import _thread + import sys + + event = _thread.allocate_lock() + event.acquire() + + def import_threading(): + import threading + event.release() + + if 'threading' in sys.modules: + raise Exception('threading is already imported') + + _thread.start_new_thread(import_threading, ()) + + # wait until the threading module is imported + event.acquire() + event.release() + + if 'threading' not in sys.modules: + raise Exception('threading is not imported') + + # don't wait until the thread completes + ''') + rc, out, err = assert_python_ok("-c", code) + self.assertEqual(out, b'') + self.assertEqual(err, b'') + class ThreadJoinOnShutdown(BaseTestCase): diff --git a/Lib/threading.py b/Lib/threading.py index f39da14..c7f7d5f 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -1523,20 +1523,29 @@ def _shutdown(): global _SHUTTING_DOWN _SHUTTING_DOWN = True - # Main thread - tlock = _main_thread._tstate_lock - # The main thread isn't finished yet, so its thread state lock can't have - # been released. - assert tlock is not None - assert tlock.locked() - tlock.release() - _main_thread._stop() # Call registered threading atexit functions before threads are joined. # Order is reversed, similar to atexit. for atexit_call in reversed(_threading_atexits): atexit_call() + # Main thread + if _main_thread.ident == get_ident(): + tlock = _main_thread._tstate_lock + # The main thread isn't finished yet, so its thread state lock can't + # have been released. + assert tlock is not None + assert tlock.locked() + tlock.release() + _main_thread._stop() + else: + # bpo-1596321: _shutdown() must be called in the main thread. + # If the threading module was not imported by the main thread, + # _main_thread is the thread which imported the threading module. + # In this case, ignore _main_thread, similar behavior than for threads + # spawned by C libraries or using _thread.start_new_thread(). + pass + # Join all non-deamon threads while True: with _shutdown_locks_lock: diff --git a/Misc/NEWS.d/next/Library/2021-09-24-17-20-23.bpo-1596321.3nhPUk.rst b/Misc/NEWS.d/next/Library/2021-09-24-17-20-23.bpo-1596321.3nhPUk.rst new file mode 100644 index 0000000..61a3e5a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-09-24-17-20-23.bpo-1596321.3nhPUk.rst @@ -0,0 +1,3 @@ +Fix the :func:`threading._shutdown` function when the :mod:`threading` module +was imported first from a thread different than the main thread: no longer log +an error at Python exit. |