Author vstinner
Recipients amaury.forgeotdarc, corona10, eric.snow, isoschiz, kylotan, lukasz.langa, miss-islington, pconnell, phsilva, santoso.wijaya, shihai1991, tlesher, vstinner, ysj.ray
Date 2020-03-25.02:41:52
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1585104113.28.0.236723933414.issue1635741@roundup.psfhosted.org>
In-reply-to
Content
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.
History
Date User Action Args
2020-03-25 02:41:53vstinnersetrecipients: + 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:53vstinnersetmessageid: <1585104113.28.0.236723933414.issue1635741@roundup.psfhosted.org>
2020-03-25 02:41:53vstinnerlinkissue1635741 messages
2020-03-25 02:41:52vstinnercreate