Message364973
Hum, some clarification is needed here.
"Port xxx extension module to multiphase initialization (PEP 489)" changes are helping to fix "Py_Finalize() doesn't clear all Python objects at exit", but alone they don't fix all issues.
--
For example, if a module still uses globals using "static ..." in C, these globals will not be cleared magically. Example with _datetimemodule.c:
static PyObject *us_per_hour = NULL; /* 1e6 * 3600 as Python int */
static PyObject *us_per_day = NULL; /* 1e6 * 3600 * 24 as Python int */
static PyObject *us_per_week = NULL; /* 1e6*3600*24*7 as Python int */
These variables initialized once in PyInit__datetime():
us_per_hour = PyLong_FromDouble(3600000000.0);
us_per_day = PyLong_FromDouble(86400000000.0);
us_per_week = PyLong_FromDouble(604800000000.0);
Converting the module to multiphase initialization will not magically clear these variables at exit. The _datetime module should be modified to store these variables in a module state: this module could be cleared at exit.
The binascii is a good example: it has a module state, traverse, clear and free methods, and it uses the multiphase initialization. This module can be fully unloaded at exit.
It's a "simple" module: it doesn't define types for example.
--
Another issue is that converting a module to the multiphase initialization doesn't magically fully isolate two instances of the module. For exmaple, the _abc module still uses a type defined statically:
static PyTypeObject _abc_data_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_abc_data", /*tp_name*/
sizeof(_abc_data), /*tp_basicsize*/
.tp_dealloc = (destructor)abc_data_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_alloc = PyType_GenericAlloc,
.tp_new = abc_data_new,
};
Example:
vstinner@apu$ ./python
Python 3.9.0a5+ (heads/pr/19122:0ac3031a80, Mar 25 2020, 02:25:19)
>>> import _abc
>>> class Bla: pass
...
>>> _abc._abc_init(Bla)
>>> type(Bla._abc_impl)
<class '_abc_data'>
# load a second instance of the module
>>> import sys; del sys.modules['_abc']
>>> import _abc as _abc2
>>> class Bla2: pass
...
>>> _abc._abc_init(Bla2)
>>> type(Bla2._abc_impl)
<class '_abc_data'>
# _abc and _abc2 have exactly the same type,
# they are not fully isolated
>>> type(Bla2._abc_impl) is type(Bla._abc_impl)
True
That's more an issue for subinterpreters: each interpreter should have its own fully isolated instance of an C extension module. |
|
Date |
User |
Action |
Args |
2020-03-25 02:41:53 | vstinner | set | recipients:
+ vstinner, amaury.forgeotdarc, kylotan, tlesher, phsilva, ysj.ray, santoso.wijaya, lukasz.langa, eric.snow, pconnell, isoschiz, corona10, miss-islington, shihai1991 |
2020-03-25 02:41:53 | vstinner | set | messageid: <1585104113.28.0.236723933414.issue1635741@roundup.psfhosted.org> |
2020-03-25 02:41:53 | vstinner | link | issue1635741 messages |
2020-03-25 02:41:52 | vstinner | create | |
|