Issue #1545463: At shutdown, defer finalization of codec modules so that stderr remains usable.

(should fix Windows buildbot failures on test_gc)
This commit is contained in:
Antoine Pitrou 2013-05-08 13:23:25 +02:00
parent d62a514386
commit 070cb3c9be
5 changed files with 96 additions and 25 deletions

View File

@ -25,6 +25,12 @@ PyAPI_FUNC(int) PyErr_WarnExplicit(
const char *module, /* UTF-8 encoded string */ const char *module, /* UTF-8 encoded string */
PyObject *registry); PyObject *registry);
PyAPI_FUNC(int)
PyErr_WarnExplicitFormat(PyObject *category,
const char *filename, int lineno,
const char *module, PyObject *registry,
const char *format, ...);
/* DEPRECATED: Use PyErr_WarnEx() instead. */ /* DEPRECATED: Use PyErr_WarnEx() instead. */
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
#define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1) #define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1)

View File

@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1?
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #1545463: At shutdown, defer finalization of codec modules so
that stderr remains usable.
- Issue #7330: Implement width and precision (ex: "%5.3s") for the format - Issue #7330: Implement width and precision (ex: "%5.3s") for the format
string of PyUnicode_FromFormat() function, original patch written by Ysj Ray. string of PyUnicode_FromFormat() function, original patch written by Ysj Ray.

View File

@ -1557,8 +1557,12 @@ _PyGC_DumpShutdownStats(void)
else else
message = "gc: %zd uncollectable objects at " \ message = "gc: %zd uncollectable objects at " \
"shutdown; use gc.set_debug(gc.DEBUG_UNCOLLECTABLE) to list them"; "shutdown; use gc.set_debug(gc.DEBUG_UNCOLLECTABLE) to list them";
if (PyErr_WarnFormat(PyExc_ResourceWarning, 0, message, /* PyErr_WarnFormat does too many things and we are at shutdown,
PyList_GET_SIZE(garbage)) < 0) the warnings module's dependencies (e.g. linecache) may be gone
already. */
if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0,
"gc", NULL, message,
PyList_GET_SIZE(garbage)))
PyErr_WriteUnraisable(NULL); PyErr_WriteUnraisable(NULL);
if (debug & DEBUG_UNCOLLECTABLE) { if (debug & DEBUG_UNCOLLECTABLE) {
PyObject *repr = NULL, *bytes = NULL; PyObject *repr = NULL, *bytes = NULL;
@ -1567,7 +1571,7 @@ _PyGC_DumpShutdownStats(void)
PyErr_WriteUnraisable(garbage); PyErr_WriteUnraisable(garbage);
else { else {
PySys_WriteStderr( PySys_WriteStderr(
" %s\n", " %s\n",
PyBytes_AS_STRING(bytes) PyBytes_AS_STRING(bytes)
); );
} }

View File

@ -800,8 +800,8 @@ PyErr_WarnExplicit(PyObject *category, const char *text,
goto exit; goto exit;
if (module_str != NULL) { if (module_str != NULL) {
module = PyUnicode_FromString(module_str); module = PyUnicode_FromString(module_str);
if (module == NULL) if (module == NULL)
goto exit; goto exit;
} }
if (category == NULL) if (category == NULL)
@ -820,6 +820,49 @@ PyErr_WarnExplicit(PyObject *category, const char *text,
return ret; return ret;
} }
int
PyErr_WarnExplicitFormat(PyObject *category,
const char *filename_str, int lineno,
const char *module_str, PyObject *registry,
const char *format, ...)
{
PyObject *message;
PyObject *module = NULL;
PyObject *filename = PyUnicode_DecodeFSDefault(filename_str);
int ret = -1;
va_list vargs;
if (filename == NULL)
goto exit;
if (module_str != NULL) {
module = PyUnicode_FromString(module_str);
if (module == NULL)
goto exit;
}
#ifdef HAVE_STDARG_PROTOTYPES
va_start(vargs, format);
#else
va_start(vargs);
#endif
message = PyUnicode_FromFormatV(format, vargs);
if (message != NULL) {
PyObject *res;
res = warn_explicit(category, message, filename, lineno,
module, registry, NULL);
Py_DECREF(message);
if (res != NULL) {
Py_DECREF(res);
ret = 0;
}
}
va_end(vargs);
exit:
Py_XDECREF(module);
Py_XDECREF(filename);
return ret;
}
PyDoc_STRVAR(warn_doc, PyDoc_STRVAR(warn_doc,
"Issue a warning, or maybe ignore it or raise an exception."); "Issue a warning, or maybe ignore it or raise an exception.");

View File

@ -295,6 +295,30 @@ static char* sys_files[] = {
NULL NULL
}; };
static int
is_essential_module(PyObject *name)
{
Py_ssize_t name_len;
char *name_str = PyUnicode_AsUTF8AndSize(name, &name_len);
if (name_str == NULL) {
PyErr_Clear();
return 0;
}
if (strcmp(name_str, "builtins") == 0)
return 1;
if (strcmp(name_str, "sys") == 0)
return 1;
/* These are all needed for stderr to still function */
if (strcmp(name_str, "codecs") == 0)
return 1;
if (strcmp(name_str, "_codecs") == 0)
return 1;
if (strncmp(name_str, "encodings.", 10) == 0)
return 1;
return 0;
}
/* Un-initialize things, as good as we can */ /* Un-initialize things, as good as we can */
@ -374,9 +398,7 @@ PyImport_Cleanup(void)
if (value->ob_refcnt != 1) if (value->ob_refcnt != 1)
continue; continue;
if (PyUnicode_Check(key) && PyModule_Check(value)) { if (PyUnicode_Check(key) && PyModule_Check(value)) {
if (PyUnicode_CompareWithASCIIString(key, "builtins") == 0) if (is_essential_module(key))
continue;
if (PyUnicode_CompareWithASCIIString(key, "sys") == 0)
continue; continue;
if (Py_VerboseFlag) if (Py_VerboseFlag)
PySys_FormatStderr( PySys_FormatStderr(
@ -392,9 +414,7 @@ PyImport_Cleanup(void)
pos = 0; pos = 0;
while (PyDict_Next(modules, &pos, &key, &value)) { while (PyDict_Next(modules, &pos, &key, &value)) {
if (PyUnicode_Check(key) && PyModule_Check(value)) { if (PyUnicode_Check(key) && PyModule_Check(value)) {
if (PyUnicode_CompareWithASCIIString(key, "builtins") == 0) if (is_essential_module(key))
continue;
if (PyUnicode_CompareWithASCIIString(key, "sys") == 0)
continue; continue;
if (Py_VerboseFlag) if (Py_VerboseFlag)
PySys_FormatStderr("# cleanup[2] %U\n", key); PySys_FormatStderr("# cleanup[2] %U\n", key);
@ -411,20 +431,15 @@ PyImport_Cleanup(void)
machinery. */ machinery. */
_PyGC_DumpShutdownStats(); _PyGC_DumpShutdownStats();
/* Next, delete sys and builtins (in that order) */ /* Next, delete all remaining modules */
value = PyDict_GetItemString(modules, "sys"); pos = 0;
if (value != NULL && PyModule_Check(value)) { while (PyDict_Next(modules, &pos, &key, &value)) {
if (Py_VerboseFlag) if (PyUnicode_Check(key) && PyModule_Check(value)) {
PySys_WriteStderr("# cleanup sys\n"); if (Py_VerboseFlag)
_PyModule_Clear(value); PySys_FormatStderr("# cleanup[3] %U\n", key);
PyDict_SetItemString(modules, "sys", Py_None); _PyModule_Clear(value);
} PyDict_SetItem(modules, key, Py_None);
value = PyDict_GetItemString(modules, "builtins"); }
if (value != NULL && PyModule_Check(value)) {
if (Py_VerboseFlag)
PySys_WriteStderr("# cleanup builtins\n");
_PyModule_Clear(value);
PyDict_SetItemString(modules, "builtins", Py_None);
} }
/* Finally, clear and delete the modules directory */ /* Finally, clear and delete the modules directory */