Am 11.05.2011 19:41, schrieb Andi Vajda:
> If these functions eventually instantiate a Thread class, even indirectly, 
> the monkey-patching may still work.

Some of the code doesn't use the threading module at all, just thread or
the internal C API. I'd have to patch the modules and C code.

> That may cover this case but what about all the others ?
> There is a reason the call has to be manual.
> 
> I've not been able to automate it before.
> Over time, I've added checks where I could but I've not found it possible to 
> cover all cases where attachCurrentThread() wasn't called.
> 
> Anyhow, try it and see if it fixes the problem you're seeing.
> If any of the objects being freed invoke user code that eventually call into 
> the JVM, the problem is going to appear again elsewhere.

I understand your reluctance to automate the attaching of Python threads
to the JVM. Explicit is better than implicit. However this is a special
case. CPython doesn't allow to control cyclic garbage collector's
threading attachment nor does CPython have a hook that is called for
newly created threads. It's hard to debug a segfault when even code like
"a = []" can trigger the bug.

The attached patch doesn't trigger the bug in my artificial test code.
I'm going to run our test suite several times. That's going to take a
while.

Christian
Index: jcc/sources/jcc.cpp
===================================================================
--- jcc/sources/jcc.cpp	(Revision 1088091)
+++ jcc/sources/jcc.cpp	(Arbeitskopie)
@@ -33,6 +33,25 @@
 
 /* JCCEnv */
 
+int jccenv_attachCurrentThread(char *name, int asDaemon)
+{
+	int result;
+    JNIEnv *jenv = NULL;
+
+    JavaVMAttachArgs attach = {
+        JNI_VERSION_1_4, name, NULL
+    };
+
+    if (asDaemon)
+        result = env->vm->AttachCurrentThreadAsDaemon((void **) &jenv, &attach);
+    else
+        result = env->vm->AttachCurrentThread((void **) &jenv, &attach);
+
+    env->set_vm_env(jenv);
+
+    return result;
+}
+
 class t_jccenv {
 public:
     PyObject_HEAD
@@ -154,21 +173,11 @@
 {
     char *name = NULL;
     int asDaemon = 0, result;
-    JNIEnv *jenv = NULL;
 
     if (!PyArg_ParseTuple(args, "|si", &name, &asDaemon))
         return NULL;
 
-    JavaVMAttachArgs attach = {
-        JNI_VERSION_1_4, name, NULL
-    };
-
-    if (asDaemon)
-        result = env->vm->AttachCurrentThreadAsDaemon((void **) &jenv, &attach);
-    else
-        result = env->vm->AttachCurrentThread((void **) &jenv, &attach);
-
-    env->set_vm_env(jenv);
+    result = jccenv_attachCurrentThread(name, asDaemon);
         
     return PyInt_FromLong(result);
 }
Index: jcc/sources/JCCEnv.cpp
===================================================================
--- jcc/sources/JCCEnv.cpp	(Revision 1088091)
+++ jcc/sources/JCCEnv.cpp	(Arbeitskopie)
@@ -318,6 +318,16 @@
                 {
                     if (iter->second.count == 1)
                     {
+                        JNIEnv *vm_env = get_vm_env();
+                        if (!vm_env)
+                        {
+                                /* Python's cyclic garbage collector may remove
+                                 * an object inside a thread that is not attached
+                                 * to the JVM. This makes sure JCC doesn't segfault.
+                                 */
+                                jccenv_attachCurrentThread(NULL, 0);
+                                vm_env = get_vm_env();
+                        }
                         get_vm_env()->DeleteGlobalRef(iter->second.global);
                         refs.erase(iter);
                     }
Index: jcc/sources/JCCEnv.h
===================================================================
--- jcc/sources/JCCEnv.h	(Revision 1088091)
+++ jcc/sources/JCCEnv.h	(Arbeitskopie)
@@ -72,6 +72,8 @@
 
 typedef jclass (*getclassfn)(void);
 
+int jccenv_attachCurrentThread(char *name, int asDaemon);
+
 class countedRef {
 public:
     jobject global;

Reply via email to