From f1dc0615e913fd0028a2fa6fda9607b3edfa76d5 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 19 Feb 1998 20:51:52 +0000 Subject: [PATCH] Add internal routine _PyModule_Clear(), which does approximately what clear_carefully() used to do in import.c. Differences: leave only __builtins__ alone in the 2nd pass; and don't clear the dictionary (on the theory that as long as there are references left to the dictionary, those might be destructors that might expect __builtins__ to be alive when they run; and __builtins__ can't normally be part of a cycle). --- Include/moduleobject.h | 1 + Objects/moduleobject.c | 51 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/Include/moduleobject.h b/Include/moduleobject.h index a435b7f54d1..03bc9f7b73c 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -44,6 +44,7 @@ extern DL_IMPORT(PyTypeObject) PyModule_Type; extern PyObject *PyModule_New Py_PROTO((char *)); extern PyObject *PyModule_GetDict Py_PROTO((PyObject *)); extern char *PyModule_GetName Py_PROTO((PyObject *)); +extern void _PyModule_Clear Py_PROTO((PyObject *)); #ifdef __cplusplus } diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 1ba1a1b7056..7a41439360d 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -93,6 +93,55 @@ PyModule_GetName(m) return PyString_AsString(nameobj); } +void +_PyModule_Clear(m) + PyObject *m; +{ + /* To make the execution order of destructors for global + objects a bit more predictable, we first zap all objects + whose name starts with a single underscore, before we clear + the entire dictionary. We zap them by replacing them with + None, rather than deleting them from the dictionary, to + avoid rehashing the dictionary (to some extent). */ + + int pos; + PyObject *key, *value; + PyObject *d; + + d = ((PyModuleObject *)m)->md_dict; + + /* 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)) { + char *s = PyString_AsString(key); + if (s[0] == '_' && s[1] != '_') { + if (Py_VerboseFlag > 1) + fprintf(stderr, "# clear[1] %s\n", s); + PyDict_SetItem(d, key, Py_None); + } + } + } + + /* Next, clear all names except for __builtins__ */ + pos = 0; + while (PyDict_Next(d, &pos, &key, &value)) { + if (value != Py_None && PyString_Check(key)) { + char *s = PyString_AsString(key); + if (s[0] != '_' || strcmp(s, "__builtins__") != 0) { + if (Py_VerboseFlag > 1) + fprintf(stderr, "# clear[2] %s\n", s); + PyDict_SetItem(d, key, Py_None); + } + } + } + + /* Note: we leave __builtins__ in place, so that destructors + of non-global objects defined in this module can still use + builtins, in particularly 'None'. */ + +} + /* Methods */ static void @@ -100,7 +149,7 @@ module_dealloc(m) PyModuleObject *m; { if (m->md_dict != NULL) { - PyDict_Clear(m->md_dict); + _PyModule_Clear((PyObject *)m); Py_DECREF(m->md_dict); } free((char *)m);