cpython: c2a13acd5e2b (original) (raw)
Mercurial > cpython
changeset 87070:c2a13acd5e2b
Close #19466: Clear the frames of daemon threads earlier during the Python shutdown to call objects destructors. So "unclosed file" resource warnings are now corretly emitted for daemon threads. [#19466]
Victor Stinner victor.stinner@gmail.com | |
---|---|
date | Tue, 12 Nov 2013 16:37:55 +0100 |
parents | cb05beabb656 |
children | 10a8e676b87b |
files | Lib/test/test_threading.py Misc/NEWS Python/pythonrun.c |
diffstat | 3 files changed, 69 insertions(+), 5 deletions(-)[+] [-] Lib/test/test_threading.py 50 Misc/NEWS 4 Python/pythonrun.c 20 |
line wrap: on
line diff
--- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -617,6 +617,52 @@ class ThreadTests(BaseTestCase): t.join() self.assertRaises(ValueError, bs.release)
- def test_locals_at_exit(self):
# Issue #19466: thread locals must not be deleted before destructors[](#l1.8)
# are called[](#l1.9)
rc, out, err = assert_python_ok("-c", """if 1:[](#l1.10)
import threading[](#l1.11)
class Atexit:[](#l1.13)
def __del__(self):[](#l1.14)
print("thread_dict.atexit = %r" % thread_dict.atexit)[](#l1.15)
thread_dict = threading.local()[](#l1.17)
thread_dict.atexit = "atexit"[](#l1.18)
atexit = Atexit()[](#l1.20)
""")[](#l1.21)
self.assertEqual(out.rstrip(), b"thread_dict.atexit = 'atexit'")[](#l1.22)
- def test_warnings_at_exit(self):
# Issue #19466: try to call most destructors at Python shutdown before[](#l1.25)
# destroying Python thread states[](#l1.26)
filename = __file__[](#l1.27)
rc, out, err = assert_python_ok("-Wd", "-c", """if 1:[](#l1.28)
import time[](#l1.29)
import threading[](#l1.30)
def open_sleep():[](#l1.32)
# a warning will be emitted when the open file will be[](#l1.33)
# destroyed (without being explicitly closed) while the daemon[](#l1.34)
# thread is destroyed[](#l1.35)
fileobj = open(%a, 'rb')[](#l1.36)
start_event.set()[](#l1.37)
time.sleep(60.0)[](#l1.38)
start_event = threading.Event()[](#l1.40)
thread = threading.Thread(target=open_sleep)[](#l1.42)
thread.daemon = True[](#l1.43)
thread.start()[](#l1.44)
# wait until the thread started[](#l1.46)
start_event.wait()[](#l1.47)
""" % filename)[](#l1.48)
self.assertRegex(err.rstrip(),[](#l1.49)
b"^sys:1: ResourceWarning: unclosed file ")[](#l1.50)
+ + class ThreadJoinOnShutdown(BaseTestCase): def _run_and_join(self, script): @@ -701,6 +747,10 @@ class ThreadJoinOnShutdown(BaseTestCase) import sys import time import threading
import warnings[](#l1.60)
# ignore "unclosed file ..." warnings[](#l1.62)
warnings.filterwarnings('ignore', '', ResourceWarning)[](#l1.63)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Projected release date: 2013-11-24 Core and Builtins ----------------- +- Issue #19466: Clear the frames of daemon threads earlier during the
- Python shutdown to call objects destructors. So "unclosed file" resource
- warnings are now corretly emitted for daemon threads. +
--- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -576,11 +576,13 @@ Py_Finalize(void) _Py_Finalizing = tstate; initialized = 0;
- /* Destroy the state of all threads except of the current thread: in
practice, only daemon threads should still be alive. Clear frames of[](#l3.13)
other threads to call objects destructor. Destructors will be called in[](#l3.14)
the current Python thread. Since _Py_Finalizing has been set, no other[](#l3.15)
Python threads can lock the GIL at this point (if they try, they will[](#l3.16)
exit immediatly). */[](#l3.17)
- _PyThreadState_DeleteExcept(tstate);
/* Collect garbage. This may call finalizers; it's nice to call these * before all modules are destroyed. @@ -595,6 +597,7 @@ Py_Finalize(void) * XXX I haven't seen a real-life report of either of these. / PyGC_Collect(); + #ifdef COUNT_ALLOCS / With COUNT_ALLOCS, it helps to run GC multiple times: each collection might release some types from the type @@ -602,6 +605,13 @@ Py_Finalize(void) while (PyGC_Collect() > 0) /* nothing */; #endif +