summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1998-01-19 21:58:26 (GMT)
committerGuido van Rossum <guido@python.org>1998-01-19 21:58:26 (GMT)
commit758eec01728e41bce41ccc31ae96a856a4de6abc (patch)
treeecaa09debf7f8f683dae54fd4ad19df087429790 /Python
parent8095ebfc4a4ca613e294db8e512908c7a54e4ac9 (diff)
downloadcpython-758eec01728e41bce41ccc31ae96a856a4de6abc.zip
cpython-758eec01728e41bce41ccc31ae96a856a4de6abc.tar.gz
cpython-758eec01728e41bce41ccc31ae96a856a4de6abc.tar.bz2
Rewritten PyImport_Cleanup() and its helper, clear_carefully(). They
now implement the following finalization strategy. 1. Whenever this code deletes a module, its directory is cleared carefully, as follows: - set all names to None that begin with exactly one underscore - set all names to None that don't begin with two underscores - clear the directory 2. Modules are deleted in the following order: - modules with a reference count of 1, except __builtin__ or __sys__ - repeat until no more are found with a reference count of 1 - __main__ if it's still there - all remaining modules except __builtin__ or sys - sys _ __builtin__
Diffstat (limited to 'Python')
-rw-r--r--Python/import.c110
1 files changed, 98 insertions, 12 deletions
diff --git a/Python/import.c b/Python/import.c
index 8e47ee9..224a3bc 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -141,6 +141,9 @@ clear_carefully(d)
int pos;
PyObject *key, *value;
+ Py_INCREF(d); /* Prevent it from being deleted recursively */
+
+ /* First, clear only names starting with a single underscore */
pos = 0;
while (PyDict_Next(d, &pos, &key, &value)) {
if (value != Py_None && PyString_Check(key)) {
@@ -149,31 +152,114 @@ clear_carefully(d)
PyDict_SetItem(d, key, Py_None);
}
}
-
- PyDict_Clear(d);
+
+ /* Next, clear all names except those starting with two underscores */
+ pos = 0;
+ while (PyDict_Next(d, &pos, &key, &value)) {
+ if (value != Py_None && PyString_Check(key)) {
+ char *s = PyString_AsString(key);
+ if (s[0] != '_' || s[1] != '_')
+ PyDict_SetItem(d, key, Py_None);
+ }
+ }
+
+ PyDict_Clear(d); /* Finally, clear all names */
+
+ Py_DECREF(d); /* Match INCREF at top */
}
+
/* Un-initialize things, as good as we can */
void
PyImport_Cleanup()
{
+ int pos, ndone;
+ char *name;
+ PyObject *key, *value, *dict;
PyInterpreterState *interp = PyThreadState_Get()->interp;
- PyObject *tmp = interp->modules;
- if (tmp != NULL) {
- int pos;
- PyObject *key, *value;
- interp->modules = NULL;
+ PyObject *modules = interp->modules;
+
+ if (modules == NULL)
+ return; /* Already done */
+
+ /* The special treatment of __builtin__ here is because even
+ when it's not referenced as a module, its dictionary is
+ referenced by almost every module's __builtins__. Since
+ deleting a module clears its dictionary (even if there are
+ references left to it), we need to delete the __builtin__
+ module last. Likewise, we don't delete sys until the very
+ end because it is implicitly referenced (e.g. by print).
+
+ Also note that we 'delete' modules by replacing their entry
+ in the modules dict with None, rather than really deleting
+ them; this avoids a rehash of the modules dictionary and
+ also marks them as "non existent" so they won't be
+ re-imported. */
+
+ /* First, repeatedly delete modules with a reference count of
+ one (skipping __builtin__ and sys) and delete them */
+ do {
+ ndone = 0;
pos = 0;
- while (PyDict_Next(tmp, &pos, &key, &value)) {
+ while (PyDict_Next(modules, &pos, &key, &value)) {
+ if (value->ob_refcnt != 1)
+ continue;
if (PyModule_Check(value)) {
- PyObject *d = PyModule_GetDict(value);
- clear_carefully(d);
+ name = PyString_AsString(key);
+ dict = PyModule_GetDict(value);
+ if (strcmp(name, "__builtin__") == 0)
+ continue;
+ if (strcmp(name, "sys") == 0)
+ continue;
+ clear_carefully(dict);
+ PyDict_SetItem(modules, key, Py_None);
+ ndone++;
}
}
- PyDict_Clear(tmp);
- Py_DECREF(tmp);
+ } while (ndone > 0);
+
+ /* Next, delete __main__ if it's still there */
+ value = PyDict_GetItemString(modules, "__main__");
+ if (value != NULL && PyModule_Check(value)) {
+ dict = PyModule_GetDict(value);
+ clear_carefully(dict);
+ PyDict_SetItemString(modules, "__main__", Py_None);
}
+
+ /* Next, delete all modules (still skipping __builtin__ and sys) */
+ pos = 0;
+ while (PyDict_Next(modules, &pos, &key, &value)) {
+ if (PyModule_Check(value)) {
+ name = PyString_AsString(key);
+ dict = PyModule_GetDict(value);
+ if (strcmp(name, "__builtin__") == 0)
+ continue;
+ if (strcmp(name, "sys") == 0)
+ continue;
+ clear_carefully(dict);
+ PyDict_SetItem(modules, key, Py_None);
+ }
+ }
+
+ /* Next, delete sys and __builtin__ (in that order) */
+ value = PyDict_GetItemString(modules, "sys");
+ if (value != NULL && PyModule_Check(value)) {
+ dict = PyModule_GetDict(value);
+ clear_carefully(dict);
+ PyDict_SetItemString(modules, "sys", Py_None);
+ }
+ value = PyDict_GetItemString(modules, "__builtin__");
+ if (value != NULL && PyModule_Check(value)) {
+ dict = PyModule_GetDict(value);
+ clear_carefully(dict);
+ PyDict_SetItemString(modules, "__builtin__", Py_None);
+ }
+
+ /* Finally, clear and delete the modules directory */
+ PyDict_Clear(modules);
+ interp->modules = NULL;
+ Py_DECREF(modules);
}