blob: ad35ff29097baeb2c1ea32c9c4388be8d6a747e1 [file] [log] [blame]
http://code.google.com/p/modwsgi/source/detail?r=637ee0510a49f5bf80fe49b2ee27158cf01855c6
http://code.google.com/p/modwsgi/source/detail?r=d40a1bf6b9ad9cacc50caf0b3806b9a231e0d4d7
--- mod_wsgi.c
+++ mod_wsgi.c
@@ -1,7 +1,7 @@
/* vim: set sw=4 expandtab : */
/*
- * Copyright 2007-2010 GRAHAM DUMPLETON
+ * Copyright 2007-2011 GRAHAM DUMPLETON
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -386,6 +386,10 @@
#define WSGI_RELOAD_MODULE 0
#define WSGI_RELOAD_PROCESS 1
+/* Python interpreter state. */
+
+static PyThreadState *wsgi_main_tstate = NULL;
+
/* Base server object. */
static server_rec *wsgi_server = NULL;
@@ -3598,7 +3602,11 @@
*/
if (!wsgi_daemon_pool && self->config->pass_apache_request) {
+#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 2
+ object = PyCapsule_New(self->r, 0, 0);
+#else
object = PyCObject_FromVoidPtr(self->r, 0);
+#endif
PyDict_SetItemString(vars, "apache.request_rec", object);
Py_DECREF(object);
}
@@ -5147,15 +5155,22 @@
PyObject *exitfunc = NULL;
PyObject *module = NULL;
+ PyThreadState *tstate_enter = NULL;
+
/*
- * We should always enter here with the Python GIL held, but
- * there will be no active thread state. Note that it should
- * be safe to always assume that the simplified GIL state
- * API lock was originally unlocked as always calling in
- * from an Apache thread outside of Python.
+ * We should always enter here with the Python GIL
+ * held and an active thread state. This should only
+ * now occur when shutting down interpreter and not
+ * when releasing interpreter as don't support
+ * recyling of interpreters within the process. Thus
+ * the thread state should be that for the main
+ * Python interpreter. Where dealing with a named
+ * sub interpreter, we need to change the thread
+ * state to that which was originally used to create
+ * that sub interpreter before doing anything.
*/
- PyEval_ReleaseLock();
+ tstate_enter = PyThreadState_Get();
if (*self->name) {
#if APR_HAS_THREADS
@@ -5194,10 +5209,13 @@
tstate = self->tstate;
#endif
- PyEval_AcquireThread(tstate);
+ /*
+ * Swap to interpreter thread state that was used when
+ * the sub interpreter was created.
+ */
+
+ PyThreadState_Swap(tstate);
}
- else
- PyGILState_Ensure();
if (self->owner) {
Py_BEGIN_ALLOW_THREADS
@@ -5492,20 +5510,7 @@
/* If we own it, we destroy it. */
- if (!self->owner) {
- if (*self->name) {
- tstate = PyThreadState_Get();
-
- PyThreadState_Clear(tstate);
- PyEval_ReleaseThread(tstate);
- PyThreadState_Delete(tstate);
- }
- else
- PyGILState_Release(PyGILState_UNLOCKED);
-
- PyEval_AcquireLock();
- }
- else {
+ if (self->owner) {
/*
* We need to destroy all the thread state objects
* associated with the interpreter. If there are
@@ -5539,6 +5544,8 @@
/* Can now destroy the interpreter. */
Py_EndInterpreter(tstate);
+
+ PyThreadState_Swap(tstate_enter);
}
free(self->name);
@@ -5647,7 +5654,14 @@
ap_log_error(APLOG_MARK, WSGI_LOG_INFO(0), wsgi_server,
"mod_wsgi (pid=%d): Terminating Python.", getpid());
- PyGILState_Ensure();
+ /*
+ * We should be executing in the main thread again at this
+ * point but without the GIL, so simply restore the original
+ * thread state for that thread that we remembered when we
+ * initialised the interpreter.
+ */
+
+ PyEval_AcquireThread(wsgi_main_tstate);
/*
* Work around bug in Python 3.X whereby it will crash if
@@ -5822,15 +5836,24 @@
/* Initialise threading. */
PyEval_InitThreads();
- PyThreadState_Swap(NULL);
- PyEval_ReleaseLock();
+
+ /*
+ * We now want to release the GIL. Before we do that
+ * though we remember what the current thread state is.
+ * We will use that later to restore the main thread
+ * state when we want to cleanup interpreters on
+ * shutdown.
+ */
+
+ wsgi_main_tstate = PyThreadState_Get();
+ PyEval_ReleaseThread(wsgi_main_tstate);
wsgi_python_initialized = 1;
- /*
- * Register cleanups to be performed on parent restart
- * or shutdown. This will destroy Python itself.
- */
+ /*
+ * Register cleanups to be performed on parent restart
+ * or shutdown. This will destroy Python itself.
+ */
#if AP_SERVER_MAJORVERSION_NUMBER < 2
ap_register_cleanup(p, NULL, wsgi_python_parent_cleanup,
@@ -5879,7 +5902,11 @@
/*
* This function should never be called when the
- * Python GIL is held, so need to acquire it.
+ * Python GIL is held, so need to acquire it. Even
+ * though we may need to work with a sub
+ * interpreter, we need to acquire GIL against main
+ * interpreter first to work with interpreter
+ * dictionary.
*/
state = PyGILState_Ensure();
@@ -5998,6 +6025,8 @@
{
PyThreadState *tstate = NULL;
+ PyGILState_STATE state;
+
/*
* Need to release and destroy the thread state that
* was created against the interpreter. This will
@@ -6023,11 +6052,11 @@
* in its destruction if its the last reference.
*/
- PyEval_AcquireLock();
+ state = PyGILState_Ensure();
Py_DECREF(handle);
- PyEval_ReleaseLock();
+ PyGILState_Release(state);
}
/*
@@ -6630,7 +6659,14 @@
apr_thread_mutex_lock(wsgi_interp_lock);
#endif
- PyEval_AcquireLock();
+ /*
+ * We should be executing in the main thread again at this
+ * point but without the GIL, so simply restore the original
+ * thread state for that thread that we remembered when we
+ * initialised the interpreter.
+ */
+
+ PyEval_AcquireThread(wsgi_main_tstate);
/*
* Extract a handle to the main Python interpreter from
@@ -6668,7 +6704,13 @@
Py_DECREF(interp);
- PyEval_ReleaseLock();
+ /*
+ * The code which performs actual shutdown of the main
+ * interpreter expects to be called without the GIL, so
+ * we release it here again.
+ */
+
+ PyEval_ReleaseThread(wsgi_main_tstate);
/*
* Destroy Python itself including the main interpreter.
@@ -8369,7 +8411,11 @@
*/
if (!wsgi_daemon_pool && self->config->pass_apache_request) {
+#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 2
+ object = PyCapsule_New(self->r, 0, 0);
+#else
object = PyCObject_FromVoidPtr(self->r, 0);
+#endif
PyDict_SetItemString(vars, "apache.request_rec", object);
Py_DECREF(object);
}
@@ -10509,6 +10555,8 @@
{
WSGIDaemonProcess *daemon = data;
+ PyGILState_STATE gilstate;
+
if (wsgi_server_config->verbose_debugging) {
ap_log_error(APLOG_MARK, WSGI_LOG_DEBUG(0), wsgi_server,
"mod_wsgi (pid=%d): Enable deadlock thread in "
@@ -10523,8 +10571,8 @@
while (1) {
apr_sleep(apr_time_from_sec(1));
- PyEval_AcquireLock();
- PyEval_ReleaseLock();
+ gilstate = PyGILState_Ensure();
+ PyGILState_Release(gilstate);
apr_thread_mutex_lock(wsgi_shutdown_lock);
wsgi_deadlock_shutdown_time = apr_time_now();
@@ -11101,6 +11149,7 @@
if (wsgi_python_after_fork)
wsgi_python_init(p);
+#if PY_MAJOR_VERSION < 3
/*
* If mod_python is also being loaded and thus it was
* responsible for initialising Python it can leave in
@@ -11110,7 +11159,9 @@
* initialisation but in daemon process we skip the
* mod_python child initialisation so the active thread
* state still exists. Thus need to do a bit of a fiddle
- * to ensure there is no active thread state.
+ * to ensure there is no active thread state. Don't need
+ * to worry about this with Python 3.X as mod_python
+ * only supports Python 2.X.
*/
if (!wsgi_python_initialized) {
@@ -11126,6 +11177,7 @@
PyEval_ReleaseLock();
}
+#endif
/*
* If the daemon is associated with a virtual host then
@@ -13372,7 +13424,11 @@
*/
if (!wsgi_daemon_pool && self->config->pass_apache_request) {
+#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 2
+ object = PyCapsule_New(self->r, 0, 0);
+#else
object = PyCObject_FromVoidPtr(self->r, 0);
+#endif
PyDict_SetItemString(vars, "apache.request_rec", object);
Py_DECREF(object);
}