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;