2007-04-27 04:27:24 -04:00
|
|
|
|
PEP: 3121
|
2007-05-03 03:00:04 -04:00
|
|
|
|
Title: Extension Module Initialization and Finalization
|
2007-04-27 04:31:58 -04:00
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
2007-04-27 04:27:24 -04:00
|
|
|
|
Author: Martin v. Löwis <martin@v.loewis.de>
|
|
|
|
|
Status: Draft
|
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 27-Apr-2007
|
|
|
|
|
Python-Version: 3.0
|
|
|
|
|
Post-History:
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
2007-05-03 03:00:04 -04:00
|
|
|
|
Extension module initialization currently has a few deficiencies.
|
|
|
|
|
There is no cleanup for modules, the entry point name might give
|
|
|
|
|
naming conflicts, the entry functions don't follow the usual calling
|
|
|
|
|
convention, and multiple interpreters are not supported well. This PEP
|
|
|
|
|
addresses these issues.
|
2007-04-27 04:27:24 -04:00
|
|
|
|
|
2007-04-29 10:17:02 -04:00
|
|
|
|
Problems
|
|
|
|
|
========
|
|
|
|
|
|
2007-04-27 04:27:24 -04:00
|
|
|
|
Module Finalization
|
2007-04-29 10:17:02 -04:00
|
|
|
|
-------------------
|
2007-04-27 04:27:24 -04:00
|
|
|
|
|
|
|
|
|
Currently, C modules are initialized usually once and then "live"
|
|
|
|
|
forever. The only exception is when Py_Finalize() is called: then
|
|
|
|
|
the initialization routine is invoked a second time. This is bad
|
|
|
|
|
from a resource management point of view: memory and other resources
|
|
|
|
|
might get allocated each time initialization is called, but there
|
|
|
|
|
is no way to reclaim them. As a result, there is currently no
|
|
|
|
|
way to completely release all resources Python has allocated.
|
|
|
|
|
|
|
|
|
|
Entry point name conflicts
|
2007-04-29 10:17:02 -04:00
|
|
|
|
--------------------------
|
2007-04-27 04:27:24 -04:00
|
|
|
|
|
|
|
|
|
The entry point is currently called init<module>. This might conflict
|
|
|
|
|
with other symbols also called init<something>. In particular,
|
|
|
|
|
initsocket is known to have conflicted in the past (this specific
|
|
|
|
|
problem got resolved as a side effect of renaming the module to
|
|
|
|
|
_socket).
|
|
|
|
|
|
|
|
|
|
Entry point signature
|
2007-04-29 10:17:02 -04:00
|
|
|
|
---------------------
|
2007-04-27 04:27:24 -04:00
|
|
|
|
|
|
|
|
|
The entry point is currently a procedure (returning void). This
|
|
|
|
|
deviates from the usual calling conventions; callers can find out
|
|
|
|
|
whether there was an error during initialization only by checking
|
|
|
|
|
PyErr_Occurred. The entry point should return a PyObject*, which will
|
|
|
|
|
be the module created, or NULL in case of an exception.
|
|
|
|
|
|
|
|
|
|
Multiple Interpreters
|
2007-04-29 10:17:02 -04:00
|
|
|
|
---------------------
|
2007-04-27 04:27:24 -04:00
|
|
|
|
|
|
|
|
|
Currently, extension modules share their state across all
|
|
|
|
|
interpreters. This allows for undesirable information leakage across
|
|
|
|
|
interpreters: one script could permanently corrupt objects in an
|
|
|
|
|
extension module, possibly breaking all scripts in other interpreters.
|
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
The module initialization routines change their signature
|
|
|
|
|
to::
|
|
|
|
|
|
|
|
|
|
PyObject *PyInit_<modulename>()
|
|
|
|
|
|
|
|
|
|
The initialization routine will be invoked once per
|
|
|
|
|
interpreter, when the module is imported. It should
|
|
|
|
|
return a new module object each time.
|
|
|
|
|
|
|
|
|
|
In order to store per-module state in C variables,
|
|
|
|
|
each module object will contain a block of memory
|
|
|
|
|
that is interpreted only by the module. The amount
|
|
|
|
|
of memory used for the module is specified at
|
|
|
|
|
the point of creation of the module.
|
|
|
|
|
|
|
|
|
|
In addition to the initialization function, a module
|
|
|
|
|
may implement a number of additional callback
|
|
|
|
|
function, which are invoked when the module's
|
|
|
|
|
tp_traverse, tp_clear, and tp_free functions are
|
|
|
|
|
invoked, and when the module is reloaded.
|
|
|
|
|
|
|
|
|
|
The entire module definition is combined in a struct
|
|
|
|
|
PyModuleDef::
|
|
|
|
|
|
|
|
|
|
struct PyModuleDef{
|
|
|
|
|
PyModuleDef_Base m_base; /* To be filled out by the interpreter */
|
|
|
|
|
Py_ssize_t m_size; /* Size of per-module data */
|
|
|
|
|
PyMethodDef *m_methods;
|
|
|
|
|
inquiry m_reload;
|
|
|
|
|
traverseproc m_traverse;
|
|
|
|
|
inquiry m_clear;
|
|
|
|
|
freefunc m_free;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Creation of a module is changed to expect an optional
|
|
|
|
|
PyModuleDef*. The module state will be
|
|
|
|
|
null-initialized.
|
|
|
|
|
|
2007-04-29 10:17:02 -04:00
|
|
|
|
Each module method will be passed the module object
|
2007-04-27 04:27:24 -04:00
|
|
|
|
as the first parameter. To access the module data,
|
|
|
|
|
a function::
|
|
|
|
|
|
|
|
|
|
void* PyModule_GetData(PyObject*);
|
|
|
|
|
|
|
|
|
|
will be provided. In addition, to lookup a module
|
|
|
|
|
more efficiently than going through sys.modules,
|
|
|
|
|
a function::
|
|
|
|
|
|
|
|
|
|
PyObject* PyState_FindModule(struct PyModuleDef*);
|
|
|
|
|
|
|
|
|
|
will be provided. This lookup function will use an
|
|
|
|
|
index located in the m_base field, to find the
|
|
|
|
|
module by index, not by name.
|
|
|
|
|
|
|
|
|
|
As all Python objects should be controlled through
|
|
|
|
|
the Python memory management, usage of "static"
|
|
|
|
|
type objects is discouraged, unless the type object
|
|
|
|
|
itself has no memory-managed state. To simplify
|
|
|
|
|
definition of heap types, a new method::
|
|
|
|
|
|
|
|
|
|
PyTypeObject* PyType_Copy(PyTypeObject*);
|
|
|
|
|
|
|
|
|
|
is added.
|
|
|
|
|
|
|
|
|
|
Example
|
|
|
|
|
=======
|
|
|
|
|
|
|
|
|
|
xxmodule.c would be changed to remove the initxx
|
|
|
|
|
function, and add the following code instead::
|
|
|
|
|
|
|
|
|
|
struct xxstate{
|
|
|
|
|
PyObject *ErrorObject;
|
|
|
|
|
PyObject *Xxo_Type;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define xxstate(o) ((struct xxstate*)PyModule_GetState(o))
|
|
|
|
|
|
|
|
|
|
static int xx_traverse(PyObject *m, visitproc v,
|
|
|
|
|
void *arg)
|
|
|
|
|
{
|
|
|
|
|
Py_VISIT(xxstate(m)->ErrorObject);
|
|
|
|
|
Py_VISIT(xxstate(m)->Xxo_Type);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int xx_clear(PyObject *m)
|
|
|
|
|
{
|
|
|
|
|
Py_CLEAR(xxstate(m)->ErrorObject);
|
|
|
|
|
Py_CLEAR(xxstate(m)->Xxo_Type);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct PyModuleDef xxmodule = {
|
|
|
|
|
{}, /* m_base */
|
|
|
|
|
sizeof(struct xxstate),
|
|
|
|
|
&xx_methods,
|
|
|
|
|
0, /* m_reload */
|
|
|
|
|
xx_traverse,
|
|
|
|
|
xx_clear,
|
|
|
|
|
0, /* m_free - not needed, since all is done in m_clear */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyObject*
|
|
|
|
|
PyInit_xx()
|
|
|
|
|
{
|
|
|
|
|
PyObject *res = PyModule_New("xx", &xxmodule);
|
|
|
|
|
if (!res) return NULL;
|
|
|
|
|
xxstate(res)->ErrorObject = PyErr_NewException("xx.error, NULL, NULL);
|
|
|
|
|
if (!xxstate(res)->ErrorObject) {
|
|
|
|
|
Py_DECREF(res);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
xxstate(res)->XxoType = PyType_Copy(&Xxo_Type);
|
|
|
|
|
if (!xxstate(res)->Xxo_Type) {
|
|
|
|
|
Py_DECREF(res);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Discussion
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
Tim Peters reports in [1]_ that PythonLabs considered such a feature
|
|
|
|
|
at one point, and lists the following additional hooks which aren't
|
|
|
|
|
currently supported in this PEP:
|
|
|
|
|
|
|
|
|
|
* when the module object is deleted from sys.modules
|
|
|
|
|
|
|
|
|
|
* when Py_Finalize is called
|
|
|
|
|
|
|
|
|
|
* when Python exits
|
|
|
|
|
|
|
|
|
|
* when the Python DLL is unloaded (Windows only)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
.. [1] Tim Peters, reporting earlier conversation about such a feature
|
|
|
|
|
http://mail.python.org/pipermail/python-3000/2006-April/000726.html
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
..
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
coding: utf-8
|
|
|
|
|
End:
|