I would like to propose the attached patch to support the use of python
sub-interpreters, which are used by mod_wsgi. If there is interest, I
can further clarify.
Pat
Index: jcc/jcc/sources/JCCEnv.h
===================================================================
--- jcc/jcc/sources/JCCEnv.h (revision 1358032)
+++ jcc/jcc/sources/JCCEnv.h (working copy)
@@ -56,9 +56,11 @@
#ifdef _jcc_shared
_DLL_IMPORT extern JCCEnv *env;
_DLL_IMPORT extern DWORD VM_ENV;
+_DLL_IMPORT extern DWORD PY_THREAD_STATE;
#else
_DLL_EXPORT extern JCCEnv *env;
_DLL_EXPORT extern DWORD VM_ENV;
+_DLL_EXPORT extern DWORD PY_THREAD_STATE;
#endif
#else
@@ -123,18 +125,28 @@
#if defined(_MSC_VER) || defined(__WIN32)
inline JNIEnv *get_vm_env() const
{
- return (JNIEnv *) TlsGetValue(VM_ENV);
+ return (JNIEnv *) (VM_ENV ? TlsGetValue(VM_ENV) : NULL);
}
+ inline PyThreadState *get_py_thread_state() const
+ {
+ return (PyThreadState *) (PY_THREAD_STATE ? TlsGetValue(PY_THREAD_STATE) : NULL);
+ }
#else
static pthread_key_t VM_ENV;
+ static pthread_key_t PY_THREAD_STATE;
inline JNIEnv *get_vm_env() const
{
- return (JNIEnv *) pthread_getspecific(VM_ENV);
+ return (JNIEnv *) (VM_ENV ? pthread_getspecific(VM_ENV) : NULL);
}
+ inline PyThreadState *get_py_thread_state() const
+ {
+ return (PyThreadState *) (PY_THREAD_STATE ? pthread_getspecific(PY_THREAD_STATE) : NULL);
+ }
#endif
void set_vm(JavaVM *vm, JNIEnv *vm_env);
void set_vm_env(JNIEnv *vm_env);
+ void set_py_thread_state(PyThreadState *);
int attachCurrentThread(char *name, int asDaemon);
jint getJNIVersion() const;
@@ -300,37 +312,55 @@
class PythonGIL {
private:
+ bool initial;
PyGILState_STATE state;
public:
PythonGIL()
{
- state = PyGILState_Ensure();
+ lock();
}
PythonGIL(JNIEnv *vm_env)
{
- state = PyGILState_Ensure();
+ lock();
env->set_vm_env(vm_env);
}
~PythonGIL()
{
- PyGILState_Release(state);
+ if (initial)
+ PyGILState_Release(state);
+ else
+ env->set_py_thread_state(PyEval_SaveThread());
}
+ private:
+ void lock()
+ {
+ PyThreadState *thread_state = env->get_py_thread_state();
+ if (!thread_state)
+ {
+ state = PyGILState_Ensure();
+ initial = true;
+ }
+ else
+ {
+ PyEval_RestoreThread(thread_state);
+ initial = false;
+ }
+ }
};
class PythonThreadState {
private:
- PyThreadState *state;
int handler;
public:
PythonThreadState(int handler=0)
{
- state = PyEval_SaveThread();
+ env->set_py_thread_state(PyEval_SaveThread());
this->handler = handler;
env->handlers += handler;
}
~PythonThreadState()
{
- PyEval_RestoreThread(state);
+ PyEval_RestoreThread(env->get_py_thread_state());
env->handlers -= handler;
}
};
Index: jcc/jcc/sources/JCCEnv.cpp
===================================================================
--- jcc/jcc/sources/JCCEnv.cpp (revision 1358032)
+++ jcc/jcc/sources/JCCEnv.cpp (working copy)
@@ -20,8 +20,10 @@
#if defined(_MSC_VER) || defined(__WIN32)
_DLL_EXPORT DWORD VM_ENV = 0;
+_DLL_EXPORT DWORD PY_THREAD_STATE = 0;
#else
pthread_key_t JCCEnv::VM_ENV = (pthread_key_t) NULL;
+pthread_key_t JCCEnv::PY_THREAD_STATE = (pthread_key_t) NULL;
#endif
#if defined(_MSC_VER) || defined(__WIN32)
@@ -204,20 +206,46 @@
void JCCEnv::set_vm_env(JNIEnv *vm_env)
{
- if (!VM_ENV)
- VM_ENV = TlsAlloc();
+ if (!VM_ENV) {
+ lock locked;
+ if (!VM_ENV)
+ VM_ENV = TlsAlloc();
+ }
TlsSetValue(VM_ENV, (LPVOID) vm_env);
}
+void JCCEnv::set_py_thread_state(PyThreadState *py_thread_state)
+{
+ if (!PY_THREAD_STATE) {
+ lock locked;
+ if (!PY_THREAD_STATE)
+ PY_THREAD_STATE = TlsAlloc();
+ }
+ TlsSetValue(PY_THREAD_STATE, (LPVOID) py_thread_state);
+}
+
#else
void JCCEnv::set_vm_env(JNIEnv *vm_env)
{
- if (!VM_ENV)
- pthread_key_create(&VM_ENV, NULL);
+ if (!VM_ENV) {
+ lock locked;
+ if (!VM_ENV)
+ pthread_key_create(&VM_ENV, NULL);
+ }
pthread_setspecific(VM_ENV, (void *) vm_env);
}
+void JCCEnv::set_py_thread_state(PyThreadState *py_thread_state)
+{
+ if (!PY_THREAD_STATE) {
+ lock locked;
+ if (!PY_THREAD_STATE)
+ pthread_key_create(&PY_THREAD_STATE, NULL);
+ }
+ pthread_setspecific(PY_THREAD_STATE, (void *) py_thread_state);
+}
+
#endif
jint JCCEnv::getJNIVersion() const