[
http://issues.apache.org/jira/browse/MODPYTHON-77?page=comments#action_12356739
]
Graham Dumpleton commented on MODPYTHON-77:
---
There are now so many different suggestions on this that it is all too
confusing.
In respect of latest suggested change to release_interpreter(), this code
wasn't based on latest code from 3.2 betas and therefore doesn't include fix
for where Python doesn't support threading at all. Ie., the base code on which
it should have been made was:
static void release_interpreter(void)
{
PyThreadState *tstate = PyThreadState_Get();
#ifdef WITH_THREAD
PyEval_ReleaseThread(tstate);
#else
PyThreadState_Swap(NULL);
#endif
PyThreadState_Delete(tstate);
}
Ie., new call to PyThreadState_Swap() not factored in.
I will refrain from posting what it perhaps should be so as not to make things
worse.
In terms of the comment smallest required change, I am currently taking this
to mean that the most minimal change is still to install first interpreter as
main_interpreter and then to change release_interpreter() as suggested in
previous post.
Before anyone else posts any code, let me independently work out some changes
from scratch and thus verify the fixes or not. :-(
The multiple interpreter concept of mod_python is broken for Python extension
modules since Python 2.3
--
Key: MODPYTHON-77
URL: http://issues.apache.org/jira/browse/MODPYTHON-77
Project: mod_python
Type: Bug
Components: core
Versions: 3.1.4
Environment: Python = 2.3
Reporter: Boyan Boyadjiev
Attachments: diff.txt, diff2.txt, diff3.txt, gil_test.c, gilstate.tar.gz,
mod_python.c, mod_python.c.diff, mod_python.h.diff, src.zip
The multiple interpreter concept of mod_python is broken for Python extension
modules since Python 2.3 because of the PEP 311 (Simplified Global
Interpreter Lock Acquisition for Extensions):
...
Limitations and Exclusions
This proposal identifies a solution for extension authors with
complex multi-threaded requirements, but that only require a
single PyInterpreterState. There is no attempt to cater for
extensions that require multiple interpreter states. At the time
of writing, no extension has been identified that requires
multiple PyInterpreterStates, and indeed it is not clear if that
facility works correctly in Python itself.
...
For mod_python this means, that complex Python extensions won't work any more
with Python = 2.3, because they are supposed to work only with the first
interpreter state initialized for the current process (a problem we
experienced). The first interpreter state is not used by mod_python after the
python_init is called.
One solution, which works fine for me, is to save the first interpreter state
into the interpreters dictionary in the function python_init
(MAIN_INTERPRETER is used as a key):
static int python_init(apr_pool_t *p, apr_pool_t *ptemp,
apr_pool_t *plog, server_rec *s)
{
...
/* initialize global Python interpreter if necessary */
if (! Py_IsInitialized())
{
/* initialze the interpreter */
Py_Initialize();
#ifdef WITH_THREAD
/* create and acquire the interpreter lock */
PyEval_InitThreads();
#endif
/* create the obCallBack dictionary */
interpreters = PyDict_New();
if (! interpreters) {
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, s,
python_init: PyDict_New() failed! No more memory?);
exit(1);
}
{
/*
Workaround PEP 311 - Simplified Global Interpreter Lock
Acquisition for Extensions
BEGIN
*/
PyObject *p = 0;
interpreterdata * idata = (interpreterdata
*)malloc(sizeof(interpreterdata));
PyThreadState* currentThreadState = PyThreadState_Get();
PyInterpreterState *istate = currentThreadState-interp;
idata-istate = istate;
/* obcallback will be created on first use */
idata-obcallback = NULL;
p = PyCObject_FromVoidPtr((void ) idata, NULL); /*p-refcout = 1*/
PyDict_SetItemString(interpreters, MAIN_INTERPRETER, p);
/*p-refcout = 2*/
Py_DECREF(p); /*p-refcout = 1*/
/*
END
Workaround PEP 311 - Simplified Global Interpreter Lock
Acquisition for Extensions
*/
}
/* Release the thread state because we will never use
* the main interpreter, only sub interpreters created later. */
PyThreadState_Swap(NULL);
#ifdef WITH_THREAD
/* release the lock; now other threads can run */
PyEval_ReleaseLock();
#endif
}