Commit fef34e31 authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #17937: Try harder to collect cyclic garbage at shutdown.

parent 20c1cdd6
...@@ -232,6 +232,10 @@ PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t); ...@@ -232,6 +232,10 @@ PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t);
/* C equivalent of gc.collect(). */ /* C equivalent of gc.collect(). */
PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void); PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void);
#ifndef Py_LIMITED_API
PyAPI_FUNC(Py_ssize_t) _PyGC_CollectNoFail(void);
#endif
/* Test if a type has a GC head */ /* Test if a type has a GC head */
#define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) #define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)
......
...@@ -10,6 +10,8 @@ What's New in Python 3.4.0 Alpha 1? ...@@ -10,6 +10,8 @@ What's New in Python 3.4.0 Alpha 1?
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #17937: Try harder to collect cyclic garbage at shutdown.
- Issue #12370: Prevent class bodies from interfering with the __class__ - Issue #12370: Prevent class bodies from interfering with the __class__
closure. closure.
......
...@@ -853,7 +853,8 @@ get_time(void) ...@@ -853,7 +853,8 @@ get_time(void)
/* This is the main function. Read this to understand how the /* This is the main function. Read this to understand how the
* collection process works. */ * collection process works. */
static Py_ssize_t static Py_ssize_t
collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable) collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable,
int nofail)
{ {
int i; int i;
Py_ssize_t m = 0; /* # objects collected */ Py_ssize_t m = 0; /* # objects collected */
...@@ -1000,11 +1001,16 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable) ...@@ -1000,11 +1001,16 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable)
} }
if (PyErr_Occurred()) { if (PyErr_Occurred()) {
if (nofail) {
PyErr_Clear();
}
else {
if (gc_str == NULL) if (gc_str == NULL)
gc_str = PyUnicode_FromString("garbage collection"); gc_str = PyUnicode_FromString("garbage collection");
PyErr_WriteUnraisable(gc_str); PyErr_WriteUnraisable(gc_str);
Py_FatalError("unexpected exception during garbage collection"); Py_FatalError("unexpected exception during garbage collection");
} }
}
/* Update stats */ /* Update stats */
if (n_collected) if (n_collected)
...@@ -1062,7 +1068,7 @@ collect_with_callback(int generation) ...@@ -1062,7 +1068,7 @@ collect_with_callback(int generation)
{ {
Py_ssize_t result, collected, uncollectable; Py_ssize_t result, collected, uncollectable;
invoke_gc_callback("start", generation, 0, 0); invoke_gc_callback("start", generation, 0, 0);
result = collect(generation, &collected, &uncollectable); result = collect(generation, &collected, &uncollectable, 0);
invoke_gc_callback("stop", generation, collected, uncollectable); invoke_gc_callback("stop", generation, collected, uncollectable);
return result; return result;
} }
...@@ -1544,6 +1550,19 @@ PyGC_Collect(void) ...@@ -1544,6 +1550,19 @@ PyGC_Collect(void)
return n; return n;
} }
Py_ssize_t
_PyGC_CollectNoFail(void)
{
Py_ssize_t n;
/* This function should only be called on interpreter shutdown, and
therefore not recursively. */
assert(!collecting);
collecting = 1;
n = collect(NUM_GENERATIONS - 1, NULL, NULL, 1);
collecting = 0;
return n;
}
void void
_PyGC_DumpShutdownStats(void) _PyGC_DumpShutdownStats(void)
......
...@@ -444,6 +444,7 @@ PyImport_Cleanup(void) ...@@ -444,6 +444,7 @@ PyImport_Cleanup(void)
/* Finally, clear and delete the modules directory */ /* Finally, clear and delete the modules directory */
PyDict_Clear(modules); PyDict_Clear(modules);
_PyGC_CollectNoFail();
interp->modules = NULL; interp->modules = NULL;
Py_DECREF(modules); Py_DECREF(modules);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment