@@ -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 |
|