diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index b4743fbd5e0..116688da5e7 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -666,6 +666,82 @@ struct PyModuleDef _PyIO_Module = { (freefunc)iomodule_free, }; + +static PyTypeObject* static_types[] = { + // Base classes + &PyIOBase_Type, + &PyIncrementalNewlineDecoder_Type, + + // PyIOBase_Type subclasses + &PyBufferedIOBase_Type, + &PyRawIOBase_Type, + &PyTextIOBase_Type, + + // PyBufferedIOBase_Type(PyIOBase_Type) subclasses + &PyBytesIO_Type, + &PyBufferedReader_Type, + &PyBufferedWriter_Type, + &PyBufferedRWPair_Type, + &PyBufferedRandom_Type, + + // PyRawIOBase_Type(PyIOBase_Type) subclasses + &PyFileIO_Type, + &_PyBytesIOBuffer_Type, +#ifdef MS_WINDOWS + &PyWindowsConsoleIO_Type, +#endif + + // PyTextIOBase_Type(PyIOBase_Type) subclasses + &PyStringIO_Type, + &PyTextIOWrapper_Type, +}; + + +void +_PyIO_Fini(void) +{ + for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types) - 1; i >= 0; i--) { + PyTypeObject *exc = static_types[i]; + _PyStaticType_Dealloc(exc); + } + + /* Interned strings */ +#define CLEAR_INTERNED(name) \ + Py_CLEAR(_PyIO_str_ ## name) + + CLEAR_INTERNED(close); + CLEAR_INTERNED(closed); + CLEAR_INTERNED(decode); + CLEAR_INTERNED(encode); + CLEAR_INTERNED(fileno); + CLEAR_INTERNED(flush); + CLEAR_INTERNED(getstate); + CLEAR_INTERNED(isatty); + CLEAR_INTERNED(locale); + CLEAR_INTERNED(newlines); + CLEAR_INTERNED(peek); + CLEAR_INTERNED(read); + CLEAR_INTERNED(read1); + CLEAR_INTERNED(readable); + CLEAR_INTERNED(readall); + CLEAR_INTERNED(readinto); + CLEAR_INTERNED(readline); + CLEAR_INTERNED(reset); + CLEAR_INTERNED(seek); + CLEAR_INTERNED(seekable); + CLEAR_INTERNED(setstate); + CLEAR_INTERNED(tell); + CLEAR_INTERNED(truncate); + CLEAR_INTERNED(write); + CLEAR_INTERNED(writable); +#undef CLEAR_INTERNED + + Py_CLEAR(_PyIO_str_nl); + Py_CLEAR(_PyIO_empty_str); + Py_CLEAR(_PyIO_empty_bytes); +} + + PyMODINIT_FUNC PyInit__io(void) { @@ -676,11 +752,6 @@ PyInit__io(void) state = get_io_state(m); state->initialized = 0; -#define ADD_TYPE(type) \ - if (PyModule_AddType(m, type) < 0) { \ - goto fail; \ - } - /* DEFAULT_BUFFER_SIZE */ if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0) goto fail; @@ -702,57 +773,34 @@ PyInit__io(void) (PyObject *) PyExc_BlockingIOError) < 0) goto fail; - /* Concrete base types of the IO ABCs. - (the ABCs themselves are declared through inheritance in io.py) - */ - ADD_TYPE(&PyIOBase_Type); - ADD_TYPE(&PyRawIOBase_Type); - ADD_TYPE(&PyBufferedIOBase_Type); - ADD_TYPE(&PyTextIOBase_Type); - - /* Implementation of concrete IO objects. */ - /* FileIO */ + // Set type base classes PyFileIO_Type.tp_base = &PyRawIOBase_Type; - ADD_TYPE(&PyFileIO_Type); - - /* BytesIO */ PyBytesIO_Type.tp_base = &PyBufferedIOBase_Type; - ADD_TYPE(&PyBytesIO_Type); - if (PyType_Ready(&_PyBytesIOBuffer_Type) < 0) - goto fail; - - /* StringIO */ PyStringIO_Type.tp_base = &PyTextIOBase_Type; - ADD_TYPE(&PyStringIO_Type); - #ifdef MS_WINDOWS - /* WindowsConsoleIO */ PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; - ADD_TYPE(&PyWindowsConsoleIO_Type); #endif - - /* BufferedReader */ PyBufferedReader_Type.tp_base = &PyBufferedIOBase_Type; - ADD_TYPE(&PyBufferedReader_Type); - - /* BufferedWriter */ PyBufferedWriter_Type.tp_base = &PyBufferedIOBase_Type; - ADD_TYPE(&PyBufferedWriter_Type); - - /* BufferedRWPair */ PyBufferedRWPair_Type.tp_base = &PyBufferedIOBase_Type; - ADD_TYPE(&PyBufferedRWPair_Type); - - /* BufferedRandom */ PyBufferedRandom_Type.tp_base = &PyBufferedIOBase_Type; - ADD_TYPE(&PyBufferedRandom_Type); - - /* TextIOWrapper */ PyTextIOWrapper_Type.tp_base = &PyTextIOBase_Type; - ADD_TYPE(&PyTextIOWrapper_Type); - /* IncrementalNewlineDecoder */ - ADD_TYPE(&PyIncrementalNewlineDecoder_Type); + // Add types + for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { + PyTypeObject *type = static_types[i]; + // Private type not exposed in the _io module + if (type == &_PyBytesIOBuffer_Type) { + if (PyType_Ready(type) < 0) { + goto fail; + } + } + else { + if (PyModule_AddType(m, type) < 0) { + goto fail; + } + } + } /* Interned strings */ #define ADD_INTERNED(name) \ @@ -785,6 +833,7 @@ PyInit__io(void) ADD_INTERNED(truncate) ADD_INTERNED(write) ADD_INTERNED(writable) +#undef ADD_INTERNED if (!_PyIO_str_nl && !(_PyIO_str_nl = PyUnicode_InternFromString("\n"))) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 7fc9d3c94ce..92c8ad079c5 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -29,6 +29,8 @@ #include "pycore_typeobject.h" // _PyTypes_InitTypes() #include "pycore_unicodeobject.h" // _PyUnicode_InitTypes() +extern void _PyIO_Fini(void); + #include // setlocale() #include // getenv() @@ -1702,6 +1704,10 @@ finalize_interp_clear(PyThreadState *tstate) /* Clear interpreter state and all thread states */ _PyInterpreterState_Clear(tstate); + if (is_main_interp) { + _PyIO_Fini(); + } + /* Clear all loghooks */ /* Both _PySys_Audit function and users still need PyObject, such as tuple. Call _PySys_ClearAuditHooks when PyObject available. */