Issue Details (XML | Word | Printable)

Key: MODPYTHON-77
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Graham Dumpleton
Reporter: Boyan Boyadjiev
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
mod_python

The multiple interpreter concept of mod_python is broken for Python extension modules since Python 2.3

Created: 02/Sep/05 06:26 PM   Updated: 02/Apr/07 11:25 AM
Return to search
Component/s: core
Affects Version/s: 3.1.4
Fix Version/s: 3.3.1

Time Tracking:
Not Specified

File Attachments:
  Size
Text File Licensed for inclusion in ASF works diff.txt 2005-09-02 08:33 PM Boyan Boyadjiev 1 kB
Text File Licensed for inclusion in ASF works diff2.txt 2005-09-03 02:21 AM Boyan Boyadjiev 2 kB
Text File Licensed for inclusion in ASF works diff3.txt 2005-09-03 02:48 AM Boyan Boyadjiev 2 kB
File Licensed for inclusion in ASF works gil_test.c 2005-09-03 09:26 PM Boyan Boyadjiev 2 kB
GZip Archive Licensed for inclusion in ASF works gilstate.tar.gz 2005-10-15 09:43 AM Graham Dumpleton 1 kB
GZip Archive Licensed for inclusion in ASF works grahamd_20051105.tar.gz 2005-11-05 01:52 PM Graham Dumpleton 16 kB
File Licensed for inclusion in ASF works mod_python.c 2005-09-02 06:30 PM Boyan Boyadjiev 67 kB
File Licensed for inclusion in ASF works mod_python.c.diff 2005-09-05 06:01 PM Boyan Boyadjiev 9 kB
File Licensed for inclusion in ASF works mod_python.h.diff 2005-09-05 06:01 PM Boyan Boyadjiev 0.5 kB
Zip Archive Licensed for inclusion in ASF works src.zip 2005-09-03 11:26 PM Boyan Boyadjiev 17 kB
Environment: Python >= 2.3

Resolution Date: 07/Mar/06 09:11 AM


 Description  « Hide
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

    }
    return OK;
}


Another change I've made in the attached file is to Py_DECREF(p) in get_interpreter, which will remove leaky reference to the PyCObject with the interpreter data. This was not a real problem, but now I see fewer leaks in BoundsChecker :-).


 All   Comments   Work Log   Change History   Subversion Commits      Sort Order: Ascending order - Click to sort in descending order
No work has yet been logged on this issue.