summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: b2bf65d)
raw | patch | inline | side by side (parent: b2bf65d)
author | Florian Forster <octo@leeloo.lan.home.verplant.org> | |
Sat, 21 Feb 2009 08:13:43 +0000 (09:13 +0100) | ||
committer | Florian Forster <octo@leeloo.lan.home.verplant.org> | |
Sat, 21 Feb 2009 08:19:07 +0000 (09:19 +0100) |
This way one thread entering the Java plugin twice, e. g. with the
following call-chain, will not detach itself from the JVM before it is
completely done with it.
The problematic situation is:
-> cjni_read
-> ALLOC JVM
-> `Read' (in Java)
-> `DispatchValues' (in Java)
-> plugin_dispatch_values
-> cjni_write
-> ALLOC JVM (this is a no-op!)
-> `Write' (in Java)
-> DEALLOC JVM
This last dealloc is prematurely, because the thread is not done with
the JVM yet: It'd like to continue and return from `DispatchValues' to
execute some more Java code..
following call-chain, will not detach itself from the JVM before it is
completely done with it.
The problematic situation is:
-> cjni_read
-> ALLOC JVM
-> `Read' (in Java)
-> `DispatchValues' (in Java)
-> plugin_dispatch_values
-> cjni_write
-> ALLOC JVM (this is a no-op!)
-> `Write' (in Java)
-> DEALLOC JVM
This last dealloc is prematurely, because the thread is not done with
the JVM yet: It'd like to continue and return from `DispatchValues' to
execute some more Java code..
src/java.c | patch | blob | history |
diff --git a/src/java.c b/src/java.c
index 74760e4d1960aaeb7ccc5c3ce2ec2208f718f8c5..6b0c2e1798816a90f0ef7613d46feb71800dc14d 100644 (file)
--- a/src/java.c
+++ b/src/java.c
typedef struct java_plugin_s java_plugin_t;
/* }}} */
+struct cjni_jvm_env_s /* {{{ */
+{
+ JNIEnv *jvm_env;
+ int reference_counter;
+};
+typedef struct cjni_jvm_env_s cjni_jvm_env_t;
+/* }}} */
+
/*
* Global variables
*/
static JavaVM *jvm = NULL;
+static pthread_key_t jvm_env_key;
static char **jvm_argv = NULL;
static size_t jvm_argc = 0;
return (-1);
}
- status = plugin_dispatch_values_async (&vl);
+ status = plugin_dispatch_values (&vl);
sfree (vl.values);
/*
* Functions
*/
+static JNIEnv *cjni_thread_attach (void) /* {{{ */
+{
+ cjni_jvm_env_t *cjni_env;
+ JNIEnv *jvm_env;
+
+ cjni_env = pthread_getspecific (jvm_env_key);
+ if (cjni_env == NULL)
+ {
+ /* This pointer is free'd in `cjni_jvm_env_destroy'. */
+ cjni_env = (cjni_jvm_env_t *) malloc (sizeof (*cjni_env));
+ if (cjni_env == NULL)
+ {
+ ERROR ("java plugin: cjni_thread_attach: malloc failed.");
+ return (NULL);
+ }
+ memset (cjni_env, 0, sizeof (*cjni_env));
+ cjni_env->reference_counter = 0;
+ cjni_env->jvm_env = NULL;
+
+ pthread_setspecific (jvm_env_key, cjni_env);
+ }
+
+ if (cjni_env->reference_counter > 0)
+ {
+ cjni_env->reference_counter++;
+ jvm_env = cjni_env->jvm_env;
+ }
+ else
+ {
+ int status;
+ JavaVMAttachArgs args;
+
+ assert (cjni_env->jvm_env == NULL);
+
+ memset (&args, 0, sizeof (args));
+ args.version = JNI_VERSION_1_2;
+
+ status = (*jvm)->AttachCurrentThread (jvm, (void *) &jvm_env, (void *) &args);
+ if (status != 0)
+ {
+ ERROR ("java plugin: cjni_thread_attach: AttachCurrentThread failed "
+ "with status %i.", status);
+ return (NULL);
+ }
+
+ cjni_env->reference_counter = 1;
+ cjni_env->jvm_env = jvm_env;
+ }
+
+ DEBUG ("java plugin: cjni_thread_attach: cjni_env->reference_counter = %i",
+ cjni_env->reference_counter);
+ assert (jvm_env != NULL);
+ return (jvm_env);
+} /* }}} JNIEnv *cjni_thread_attach */
+
+static int cjni_thread_detach (void) /* {{{ */
+{
+ cjni_jvm_env_t *cjni_env;
+ int status;
+
+ cjni_env = pthread_getspecific (jvm_env_key);
+ if (cjni_env == NULL)
+ {
+ ERROR ("java plugin: cjni_thread_detach: pthread_getspecific failed.");
+ return (-1);
+ }
+
+ assert (cjni_env->reference_counter > 0);
+ assert (cjni_env->jvm_env != NULL);
+
+ cjni_env->reference_counter--;
+ DEBUG ("java plugin: cjni_thread_detach: cjni_env->reference_counter = %i",
+ cjni_env->reference_counter);
+
+ if (cjni_env->reference_counter > 0)
+ return (0);
+
+ status = (*jvm)->DetachCurrentThread (jvm);
+ if (status != 0)
+ {
+ ERROR ("java plugin: cjni_thread_detach: DetachCurrentThread failed "
+ "with status %i.", status);
+ }
+
+ cjni_env->reference_counter = 0;
+ cjni_env->jvm_env = NULL;
+
+ return (0);
+} /* }}} JNIEnv *cjni_thread_attach */
+
+static void cjni_jvm_env_destroy (void *args) /* {{{ */
+{
+ cjni_jvm_env_t *cjni_env;
+
+ if (args == NULL)
+ return;
+
+ cjni_env = (cjni_jvm_env_t *) args;
+
+ if (cjni_env->reference_counter > 0)
+ {
+ ERROR ("java plugin: cjni_jvm_env_destroy: "
+ "cjni_env->reference_counter = %i;", cjni_env->reference_counter);
+ }
+
+ if (cjni_env->jvm_env != NULL)
+ {
+ ERROR ("java plugin: cjni_jvm_env_destroy: cjni_env->jvm_env = %p;",
+ (void *) cjni_env->jvm_env);
+ }
+
+ /* The pointer is allocated in `cjni_thread_attach' */
+ free (cjni_env);
+} /* }}} void cjni_jvm_env_destroy */
+
static int cjni_config_add_jvm_arg (oconfig_item_t *ci) /* {{{ */
{
char **tmp;
static int cjni_read (void) /* {{{ */
{
JNIEnv *jvm_env;
- JavaVMAttachArgs args;
int status;
if (jvm == NULL)
return (-1);
}
- jvm_env = NULL;
- memset (&args, 0, sizeof (args));
- args.version = JNI_VERSION_1_2;
-
- status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args);
- if (status != 0)
- {
- ERROR ("java plugin: cjni_read: AttachCurrentThread failed with status %i.",
- status);
+ jvm_env = cjni_thread_attach ();
+ if (jvm_env == NULL)
return (-1);
- }
cjni_read_plugins (jvm_env);
- status = (*jvm)->DetachCurrentThread (jvm);
+ status = cjni_thread_detach ();
if (status != 0)
- {
- ERROR ("java plugin: cjni_read: DetachCurrentThread failed with status %i.",
- status);
return (-1);
- }
return (0);
} /* }}} int cjni_read */
static int cjni_write (const data_set_t *ds, const value_list_t *vl) /* {{{ */
{
JNIEnv *jvm_env;
- JavaVMAttachArgs args;
int status;
if (jvm == NULL)
@@ -1470,27 +1580,15 @@ static int cjni_write (const data_set_t *ds, const value_list_t *vl) /* {{{ */
return (-1);
}
- jvm_env = NULL;
- memset (&args, 0, sizeof (args));
- args.version = JNI_VERSION_1_2;
-
- status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args);
- if (status != 0)
- {
- ERROR ("java plugin: cjni_write: AttachCurrentThread failed with status %i.",
- status);
+ jvm_env = cjni_thread_attach ();
+ if (jvm_env == NULL)
return (-1);
- }
cjni_write_plugins (jvm_env, ds, vl);
- status = (*jvm)->DetachCurrentThread (jvm);
+ status = cjni_thread_detach ();
if (status != 0)
- {
- ERROR ("java plugin: cjni_write: DetachCurrentThread failed with status %i.",
- status);
return (-1);
- }
return (0);
} /* }}} int cjni_write */
jvm = NULL;
jvm_env = NULL;
+ pthread_key_delete (jvm_env_key);
+
for (i = 0; i < jvm_argc; i++)
{
sfree (jvm_argv[i]);
if (jvm != NULL)
return (0);
+ status = pthread_key_create (&jvm_env_key, cjni_jvm_env_destroy);
+ if (status != 0)
+ {
+ ERROR ("java plugin: cjni_init: pthread_key_create failed "
+ "with status %i.", status);
+ return (-1);
+ }
+
jvm_env = NULL;
memset (&vm_args, 0, sizeof (vm_args));