bpo-19466: Py_Finalize() clears daemon threads earlier (GH-18848) · python/cpython@9ad58ac (original) (raw)

Original file line number Diff line number Diff line change
@@ -759,6 +759,51 @@ def test_shutdown_locks(self):
759 759 # Daemon threads must never add it to _shutdown_locks.
760 760 self.assertNotIn(tstate_lock, threading._shutdown_locks)
761 761
762 +def test_locals_at_exit(self):
763 +# bpo-19466: thread locals must not be deleted before destructors
764 +# are called
765 +rc, out, err = assert_python_ok("-c", """if 1:
766 + import threading
767 +
768 + class Atexit:
769 + def __del__(self):
770 + print("thread_dict.atexit = %r" % thread_dict.atexit)
771 +
772 + thread_dict = threading.local()
773 + thread_dict.atexit = "value"
774 +
775 + atexit = Atexit()
776 + """)
777 +self.assertEqual(out.rstrip(), b"thread_dict.atexit = 'value'")
778 +
779 +def test_warnings_at_exit(self):
780 +# bpo-19466: try to call most destructors at Python shutdown before
781 +# destroying Python thread states
782 +filename = __file__
783 +rc, out, err = assert_python_ok("-Wd", "-c", """if 1:
784 + import time
785 + import threading
786 + from test import support
787 +
788 + def open_sleep():
789 + # a warning will be emitted when the open file will be
790 + # destroyed (without being explicitly closed) while the daemon
791 + # thread is destroyed
792 + fileobj = open(%a, 'rb')
793 + start_event.set()
794 + time.sleep(support.LONG_TIMEOUT)
795 +
796 + start_event = threading.Event()
797 +
798 + thread = threading.Thread(target=open_sleep, daemon=True)
799 + thread.start()
800 +
801 + # wait until the thread started
802 + start_event.wait()
803 + """ % filename)
804 +self.assertRegex(err.rstrip(),
805 +b"^sys:1: ResourceWarning: unclosed file ")
806 +
762 807
763 808 class ThreadJoinOnShutdown(BaseTestCase):
764 809