summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog34
-rw-r--r--TODO26
-rw-r--r--configure.in19
-rw-r--r--native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c16
-rw-r--r--native/jni/gtk-peer/gthread-jni.c462
-rw-r--r--native/jni/gtk-peer/gthread-jni.h1
6 files changed, 467 insertions, 91 deletions
diff --git a/ChangeLog b/ChangeLog
index 1e0aa188b..2d70d142a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,39 @@
2003-02-15 Julian Dolby <dolby@us.ibm.com>
+ * configure.in (portable-native-sync): new configure option allows
+ user to configure native AWT peers to use Java threading primitives
+ instead of pthread primitives.
+ * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c
+ (Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit): get JavaVM
+ reference before calling g_thread_init if using PORTABLE_NATIVE_SYNC
+ * native/jni/gtk-peer/gthread-jni.c
+ (maybe_rethrow): utility method checks for JNI exception and throws
+ another exception (maybe it should clear the previous first?)
+ (allocatePlainObject): new method used to create a mutex
+ (freePlainObject): new method use to free a mutex
+ (takeLock): new method
+ (releaseLock): new method
+ (g_mutex_new_jni_impl): uses allocatePlainObject instead
+ (g_mutex_lock_jni_impl): uses takeLock instead
+ (g_mutex_unlock_jni_impl): uses releaseLock instead
+ (g_mutex_free_jni_impl): uses freePlainObject instead
+ (g_private_new_jni_impl): implemented
+ (g_private_get_jni_impl): implemented
+ (g_private_set_jni_impl): implemented
+ (g_cond_new_jni_impl): implemented; uses allocatePlainObject
+ (g_cond_signal_jni_impl): implemented
+ (g_cond_broadcast_jni_impl): implemented
+ (g_cond_wait_jni_impl): implemented
+ (g_cond_timed_wait_jni_impl): implemented
+ (g_cond_free_jni_impl): implemented; uses freePlainObject
+ * native/jni/gtk-peer/gthread-jni.h: extern JavaVM *gdk_vm
+
+2003-02-15 C. Brian Jones <cbj@gnu.org>
+
+ * TODO: updated
+
+2003-02-15 Julian Dolby <dolby@us.ibm.com>
+
* java/util/zip/InflaterInputStream.java (markSupported): added method
(mark): added method
(reset): added method
diff --git a/TODO b/TODO
index 67af46717..f0ac23906 100644
--- a/TODO
+++ b/TODO
@@ -1,13 +1,14 @@
The Classpath TODO list as of 2002/05/05
--- Modify Classpath build to support libgcj out of the box. Ideally
- the gcj folks could simply include a stock classpath in one of their
- distribution subdirectories, have their master configure run a configure
- on Classpath the appropriate arguments, and everything would build.
+-- Write Mauve (http://sourceware.cygnus.com/mauve/) tests for those
+ classes that don't have them.
+
+-- Write Java 2 packages not currently included or improve existing
+ ones.
-- Modify ClassLoader.getSystemResource() to support loading classes
from zip files in the CLASSPATH. This requires java.util.zip to
- be integrated first. Jar filed can probably be treated as zip
+ be integrated first. Jar files can probably be treated as zip
files for now.
-- Continue comparison and merge of classes between Classpath and GCJ.
@@ -27,12 +28,6 @@ The Classpath TODO list as of 2002/05/05
-- Update the GNU Classpath Hacker's Guide. There is a master texinfo
file in the doc/ directory in Classpath CVS.
--- Write Mauve (http://sourceware.cygnus.com/mauve/) tests for those
- classes that don't have them.
-
--- Write Java 2 packages not currently included or improve existing
- ones.
-
-- Audit the code to identify methods that do not have Javadoc comments
and/or comments that are incomplete. All input parameters, return
values, etc should be documentes. Also look for Javadoc comments on
@@ -64,13 +59,14 @@ The Classpath TODO list as of 2002/05/05
JDK 1.1 version. You can obtain that variable value using the
serialver command.
--- Do real life serialization compatibility tests of our code with Kaffe
- and the JDK.
+-- Do real life serialization compatibility tests of our code vs
+ the JDK using serialcompat from Japitools.
-- Audit code for thread safety.
--- Update the packaging of Classpath to make sure that we can build
- good distribution tarballs.
+-- Audit Java code for proper Security implementation.
+
+-- Audit native code for security, memory handling, etc.
-- Bug reports are always welcome. They are double welcome if they
are accompanied by a Mauve test that reproduces the bug.
diff --git a/configure.in b/configure.in
index b61bc3e2f..dc2de57c9 100644
--- a/configure.in
+++ b/configure.in
@@ -247,6 +247,25 @@ CLASSPATH_WITH_ZIP
CLASSPATH_ENABLE_GJDOC
+dnl -----------------------------------------------------------
+dnl -----------------------------------------------------------
+AC_ARG_ENABLE(portable-native-sync,
+[ --enable-portable-native-sync synchronize VM threads portably],
+[case "${enableval}" in
+ yes)
+ AC_DEFINE(PORTABLE_NATIVE_SYNC, 1, [Define to 1 if you want to synchronize VM threads portably])
+ ;;
+
+ no) ;;
+
+ *)
+ AC_MSG_ERROR(bad value ${enableval} for --enable-portable-native-sync)
+ ;;
+esac],
+[])
+
+dnl -----------------------------------------------------------
+
AC_OUTPUT(Makefile
doc/Makefile
doc/api/Makefile
diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c
index af14f0be8..0fe178767 100644
--- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c
+++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c
@@ -56,6 +56,10 @@ jmethodID postItemEventID;
jmethodID postListItemEventID;
JNIEnv *gdk_env;
+#ifdef PORTABLE_NATIVE_SYNC
+JavaVM *gdk_vm;
+#endif
+
/*
* Call gtk_init. It is very important that this happen before any other
* gtk calls.
@@ -81,7 +85,12 @@ Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit (JNIEnv *env, jclass clazz)
/* until we have JDK 1.2 JNI, assume we have a VM with threads that
match what GLIB was compiled for */
- g_thread_init (NULL);
+#ifdef PORTABLE_NATIVE_SYNC
+ (*env)->GetJavaVM( env, &gdk_vm );
+ g_thread_init ( &g_thread_jni_functions );
+#else
+ g_thread_init ( NULL );
+#endif
gtk_init (&argc, &argv);
@@ -101,7 +110,7 @@ Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit (JNIEnv *env, jclass clazz)
rcpath = (char *) malloc (strlen (homedir) + strlen (RC_FILE) + 2);
sprintf (rcpath, "%s/%s", homedir, RC_FILE);
}
-
+
gtk_rc_parse ((rcpath) ? rcpath : RC_FILE);
if (rcpath)
@@ -114,10 +123,13 @@ Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit (JNIEnv *env, jclass clazz)
/* "gnu/java/awt/peer/gtk/GtkGenericPeer"); */
gtkcomponentpeer = (*env)->FindClass (env,
"gnu/java/awt/peer/gtk/GtkComponentPeer");
+
gtkwindowpeer = (*env)->FindClass (env,
"gnu/java/awt/peer/gtk/GtkWindowPeer");
+
gtkscrollbarpeer = (*env)->FindClass (env,
"gnu/java/awt/peer/gtk/GtkScrollbarPeer");
+
gtklistpeer = (*env)->FindClass (env, "gnu/java/awt/peer/gtk/GtkListPeer");
gtkmenuitempeer = (*env)->FindClass (env, "gnu/java/awt/peer/gtk/GtkMenuItemPeer");
/* gdkColor = (*env)->FindClass (env, */
diff --git a/native/jni/gtk-peer/gthread-jni.c b/native/jni/gtk-peer/gthread-jni.c
index 9409720f9..01a6b3075 100644
--- a/native/jni/gtk-peer/gthread-jni.c
+++ b/native/jni/gtk-peer/gthread-jni.c
@@ -35,116 +35,430 @@ this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
+/************************************************************************/
+/* Header */
+/************************************************************************/
+
+/*
+ * Julian Dolby (dolby@us.ibm.com)
+ * February 7, 2003
+ *
+ * This code implements the GThreadFunctions interface for GLIB using
+ * Java threading primitives. All of the locking and conditional variable
+ * functionality required by GThreadFunctions is implemented using the
+ * monitor and wait/notify functionality of Java objects. The thread-
+ * local fucntionality uses the java.lang.ThreadLocal class.
+ *
+ * This code is designed to be portable in that it makes no assumptions
+ * about the underlying VM beyond that it implements the JNI functionality
+ * that this code uses.
+ *
+ * The one piece that does not really work is trylock for mutexes. The
+ * Java locking model does not include such functionality, and I do not
+ * see how to implement it without knowing something about how the VM
+ * implements locking.
+ *
+ * NOTES:
+ *
+ * I have tested it only on JikesRVM---the CVS head as of early February
+ * 2003.
+ *
+ * Currently, use of this code is governed by the configuration option
+ * --enable-portable-native-sync
+ *
+ */
+
+
+/************************************************************************/
+/* Global data */
+/************************************************************************/
#include "gthread-jni.h"
-/*
- * This code has been written specifically to be used with GTK+ 1.2.
- * `Real' GLIB threading is not supported. We fake things where necessary.
- * Once we know we're running on a 1.2 VM, we can write a real implementation.
+/* The VM handle. This is set in GtkToolkitMain.gtkInit */
+JavaVM *gdk_vm;
+
+
+/************************************************************************/
+/* Utilities to reflect exceptions back to the VM */
+/************************************************************************/
+
+/* This function checks for a pending exception, and rethrows it with
+ * a wrapper RuntimeException to deal with possible type problems (in
+ * case some calling piece of code does not expect the exception being
+ * thrown) and to include the given extra message.
*/
+static void maybe_rethrow(JNIEnv *gdk_env, char *message, char *file, int line) {
+ jthrowable cause;
-static GMutex *
-g_mutex_new_jni_impl (void)
-{
+ /* rethrow if an exception happened */
+ if ((cause = (*gdk_env)->ExceptionOccurred(gdk_env)) != NULL) {
+ jstring jmessage;
+ jclass obj_class;
+ jobject obj;
+ jmethodID ctor;
+
+ /* allocate local message in Java */
+ int len = strlen(message) + strlen(file) + 25;
+ char buf[ len ];
+ bzero(buf, len);
+ sprintf(buf, "%s (at %s:%d)", message, file, line);
+ jmessage = (*gdk_env)->NewStringUTF(gdk_env, buf);
+
+ /* create RuntimeException wrapper object */
+ obj_class = (*gdk_env)->FindClass (gdk_env, "java/lang/RuntimeException");
+ ctor = (*gdk_env)->GetMethodID(gdk_env, obj_class, "<init>", "(Ljava/langString;Ljava/lang/Throwable)V");
+ obj = (*gdk_env)->NewObject (gdk_env, obj_class, ctor, jmessage, cause);
+
+ /* throw it */
+ (*gdk_env)->Throw(gdk_env, (jthrowable)obj);
+ }
+}
+
+/* This macro is used to include a source location in the exception message */
+#define MAYBE_RETHROW(_class, _message) \
+maybe_rethrow(_class, _message, __FILE__, __LINE__)
+
+
+/************************************************************************/
+/* Utilities to allocate and free java.lang.Objects */
+/************************************************************************/
+
+/* Both the mutexes and the condition variables are java.lang.Object objects,
+ * which this method allocates and returns a global ref. Note that global
+ * refs must be explicitly freed (isn't C fun?).
+ */
+static jobject *allocatePlainObject() {
jclass obj_class;
- jobject *mutex;
+ jobject *obj;
+ JNIEnv *gdk_env;
+ jmethodID ctor;
+
+ (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
obj_class = (*gdk_env)->FindClass (gdk_env, "java/lang/Object");
- if (obj_class == NULL)
- return NULL;
-
- mutex = (jobject *) g_malloc (sizeof (jobject));
- *mutex = (*gdk_env)->AllocObject (gdk_env, obj_class);
- if (*mutex == NULL)
- {
- g_free (mutex);
- return NULL;
- }
- *mutex = (*gdk_env)->NewGlobalRef (gdk_env, *mutex);
+ MAYBE_RETHROW(gdk_env, "cannot find Object");
+
+ ctor = (*gdk_env)->GetMethodID(gdk_env, obj_class, "<init>", "()V");
+ MAYBE_RETHROW(gdk_env, "cannot find constructor");
+
+ obj = (jobject *) g_malloc (sizeof (jobject));
+ *obj = (*gdk_env)->NewObject (gdk_env, obj_class, ctor);
+ MAYBE_RETHROW(gdk_env, "cannot allocate object");
+
+ *obj = (*gdk_env)->NewGlobalRef (gdk_env, *obj);
+ MAYBE_RETHROW(gdk_env, "cannot make global ref");
- return (GMutex *) mutex;
+ return obj;
}
-static void
-g_mutex_lock_jni_impl (GMutex *mutex)
-{
- if (mutex && mutex == gdk_threads_mutex)
- (*gdk_env)->MonitorEnter (gdk_env, *((jobject *)mutex));
+/* Frees a Java object given a global ref (isn't C fun?) */
+static void freePlainObject(jobject *obj) {
+ JNIEnv *gdk_env;
+
+ if (obj) {
+ (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
+
+ (*gdk_env)->DeleteGlobalRef (gdk_env, *obj);
+ MAYBE_RETHROW(gdk_env, "cannot delete global ref");
+
+ g_free (obj);
+ }
}
-static gboolean
-g_mutex_trylock_jni_impl (GMutex *mutex)
-{
+
+/************************************************************************/
+/* Locking code */
+/************************************************************************/
+
+/* Lock a Java object */
+static void takeLock(JNIEnv *gdk_env, void *mutex) {
+ (*gdk_env)->MonitorEnter (gdk_env, *((jobject *)mutex));
+ MAYBE_RETHROW(gdk_env, "cannot get lock");
+}
+
+/* Unlock a Java object */
+static void releaseLock(JNIEnv *gdk_env, void *mutex) {
+ (*gdk_env)->MonitorExit (gdk_env, *((jobject *)mutex));
+ MAYBE_RETHROW(gdk_env, "cannot release lock");
+}
+
+/* Create a mutex, which is a java.lang.Object for us */
+static GMutex *g_mutex_new_jni_impl (void) {
+ return (GMutex*) allocatePlainObject();
+}
+
+/* Lock a mutex. */
+static void g_mutex_lock_jni_impl (GMutex *mutex) {
+ JNIEnv *gdk_env;
+
+ (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
+
+ takeLock(gdk_env, mutex);
+}
+
+/* Try to lock a mutex. Actually, do not try because Java objects
+ * do not provide such an interface. To be at least minimally correct,
+ * pretend we tried and failed.
+ */
+static gboolean g_mutex_trylock_jni_impl (GMutex *mutex) {
+ // Shall we implement this in a JikesRVM-specific way under a flag?
return FALSE;
}
-static void
-g_mutex_unlock_jni_impl (GMutex *mutex)
-{
- if (mutex && mutex == gdk_threads_mutex)
- (*gdk_env)->MonitorExit (gdk_env, *((jobject *)mutex));
+/* Unlock a mutex. */
+static void g_mutex_unlock_jni_impl (GMutex *mutex) {
+ JNIEnv *gdk_env;
+
+ (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
+
+ releaseLock(gdk_env, mutex);
}
-static void
-g_mutex_free_jni_impl (GMutex *mutex)
+/* Free a mutex (isn't C fun?) */
+static void g_mutex_free_jni_impl (GMutex *mutex)
{
- if (mutex && mutex == gdk_threads_mutex)
- {
- (*gdk_env)->DeleteGlobalRef (gdk_env, *((jobject *)mutex));
- g_free (mutex);
- }
+ freePlainObject( (jobject*)mutex );
}
-static GPrivate *
-g_private_new_jni_impl (GDestroyNotify notify)
-{
- return NULL;
+
+/************************************************************************/
+/* Condition variable code */
+/************************************************************************/
+
+/* Create a new condition variable. This is a java.lang.Object for us. */
+static GCond *g_cond_new_jni_impl () {
+ return (GCond*)allocatePlainObject();
}
-static gpointer
-g_private_get_jni_impl (GPrivate *private)
-{
- return NULL;
+/* Signal on a condition variable. This is simply calling Object.notify
+ * for us.
+ */
+static void g_cond_signal_jni_impl (GCond *cond) {
+ jclass lcl_class;
+ jmethodID signal_mth;
+ JNIEnv *gdk_env;
+
+ (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
+
+ lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Object");
+ MAYBE_RETHROW(gdk_env, "cannot find Object");
+
+ signal_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "notify", "()V");
+ MAYBE_RETHROW(gdk_env, "cannot find Object.<notify>");
+
+ /* Must have locked an object to call notify */
+ takeLock(gdk_env, cond);
+
+ (*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)cond, signal_mth);
+ MAYBE_RETHROW(gdk_env, "cannot signal mutex");
+
+ releaseLock(gdk_env, cond);
}
-static void
-g_private_set_jni_impl (GPrivate *private, gpointer data)
-{
+/* Broadcast to all waiting on a condition variable. This is simply
+ * calling Object.notifyAll for us.
+ */
+static void g_cond_broadcast_jni_impl (GCond *cond) {
+ jclass lcl_class;
+ jmethodID bcast_mth;
+ JNIEnv *gdk_env;
+
+ (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
+
+ lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Object");
+ MAYBE_RETHROW(gdk_env, "cannot find Object");
+
+ bcast_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "notifyAll", "()V");
+ MAYBE_RETHROW(gdk_env, "cannot find Object.<notifyAll>");
+
+ /* Must have locked an object to call notifyAll */
+ takeLock(gdk_env, cond);
+
+ (*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)cond, bcast_mth);
+ MAYBE_RETHROW(gdk_env, "cannot broadcast to mutex");
+
+ releaseLock(gdk_env, cond);
}
-static GCond *
-g_cond_new_jni_impl ()
-{
- return NULL;
+
+/* Wait on a condition variable. For us, this simply means call
+ * Object.wait.
+ */
+static void g_cond_wait_jni_impl (GCond *cond, GMutex *mutex) {
+ jclass lcl_class;
+ jmethodID wait_mth;
+ JNIEnv *gdk_env;
+
+ (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
+
+ lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Object");
+ MAYBE_RETHROW(gdk_env, "cannot find Object");
+
+ wait_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "wait", "()V");
+ MAYBE_RETHROW(gdk_env, "cannot find Object.<wait>");
+
+ /* Must have locked an object to call wait */
+ takeLock(gdk_env, cond);
+
+ (*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)cond, wait_mth);
+ MAYBE_RETHROW(gdk_env, "cannot wait on mutex");
+
+ releaseLock(gdk_env, cond);
}
-static void
-g_cond_signal_jni_impl (GCond *cond)
-{
+/* Wait on a condition vairable until a timeout. This is a little tricky
+ * for us. We first call Object.wait(J) giving it the appropriate timeout
+ * value. On return, we check whether an InterruptedException happened. If
+ * so, that is Java-speak for wait timing out.
+ */
+static gboolean
+g_cond_timed_wait_jni_impl (GCond *cond, GMutex *mutex, GTimeVal *end_time) {
+ jclass lcl_class;
+ jmethodID wait_mth;
+ JNIEnv *gdk_env;
+ jlong time;
+ jthrowable cause;
+
+ (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
+
+ lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Object");
+ MAYBE_RETHROW(gdk_env, "cannot find Object");
+
+ wait_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "wait", "(J)V");
+ MAYBE_RETHROW(gdk_env, "cannot find Object.<wait(J)>");
+
+ time = end_time->tv_sec*1000;
+ time += end_time->tv_usec/1000;
+
+ /* Must have locked an object to call wait */
+ takeLock(gdk_env, cond);
+
+ (*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)cond, wait_mth, time);
+
+ if ((cause = (*gdk_env)->ExceptionOccurred(gdk_env)) != NULL) {
+ jclass intr = (*gdk_env)->FindClass (gdk_env, "java.lang.InterruptedException");
+ if ( (*gdk_env)->IsInstanceOf(gdk_env, cause, intr) ) {
+ releaseLock(gdk_env, cond);
+ return FALSE;
+ } else {
+ MAYBE_RETHROW(gdk_env, "error in timed wait");
+ }
+ }
+
+ releaseLock(gdk_env, cond);
+
+ return TRUE;
}
-static void
-g_cond_broadcast_jni_impl (GCond *cond)
-{
+/* Free a condition variable. (isn't C fun?) */
+static void g_cond_free_jni_impl (GCond *cond) {
+ freePlainObject( (jobject*)cond );
}
-static void
-g_cond_wait_jni_impl (GCond *cond, GMutex *mutex)
-{
+
+/************************************************************************/
+/* Thread-local data code */
+/************************************************************************/
+
+/* Create a new thread-local key. We use java.lang.ThreadLocal objects
+ * for this.
+ */
+static GPrivate *g_private_new_jni_impl (GDestroyNotify notify) {
+ jclass lcl_class;
+ jobject *local;
+ JNIEnv *gdk_env;
+ jmethodID ctor;
+
+ (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
+
+ lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.ThreadLocal");
+ MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal");
+
+ ctor = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "<init>", "()V");
+ MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal.<init>");
+
+ local = (jobject *) g_malloc (sizeof (jobject));
+ *local = (*gdk_env)->NewObject(gdk_env, lcl_class, ctor);
+ MAYBE_RETHROW(gdk_env, "cannot allocate a ThreadLocal");
+
+ *local = ((*gdk_env)->NewGlobalRef (gdk_env, *local));
+ MAYBE_RETHROW(gdk_env, "cannot create a GlobalRef");
+
+ return (GPrivate*) local;
}
-static gboolean
-g_cond_timed_wait_jni_impl (GCond *cond, GMutex *mutex)
-{
- return FALSE;
+/* Get this thread's value for a thread-local key. This is simply
+ * ThreadLocal.get for us.
+ */
+static gpointer g_private_get_jni_impl (GPrivate *private) {
+ jclass lcl_class;
+ jobject lcl_obj;
+ JNIEnv *gdk_env;
+ jmethodID get_mth;
+ jclass int_class;
+ jmethodID val_mth;
+ jint int_val;
+
+ (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
+
+ lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.ThreadLocal");
+ MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal");
+
+ get_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "get", "()Ljava/lang/Object;");
+ MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal.<get>");
+
+ lcl_obj = (*gdk_env)->CallObjectMethod(gdk_env, *(jobject*)private, get_mth);
+ MAYBE_RETHROW(gdk_env, "cannot find thread-local object");
+
+ int_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Integer");
+ MAYBE_RETHROW(gdk_env, "cannot find Integer");
+
+ val_mth = (*gdk_env)->GetMethodID(gdk_env, int_class, "intValue", "()I");
+ MAYBE_RETHROW(gdk_env, "cannot find Integer.<intValue>");
+
+ int_val = (*gdk_env)->CallIntMethod(gdk_env, lcl_obj, val_mth);
+ MAYBE_RETHROW(gdk_env, "cannot get thread local value");
+
+ return (gpointer) int_val;
}
-static void
-g_cond_free_jni_impl (GCond *cond)
-{
+/* Set this thread's value for a thread-local key. This is simply
+ * ThreadLocal.set for us.
+ */
+static void g_private_set_jni_impl (GPrivate *private, gpointer data) {
+ jclass lcl_class, int_class;
+ jobject lcl_obj;
+ JNIEnv *gdk_env;
+ jmethodID new_int, set_mth;
+
+ (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
+
+ int_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Integer");
+ MAYBE_RETHROW(gdk_env, "cannot find Integer");
+
+ new_int = (*gdk_env)->GetMethodID(gdk_env, int_class, "<init>", "(I)V");
+ MAYBE_RETHROW(gdk_env, "cannot find Integer.<init>");
+
+ lcl_obj = (*gdk_env)->NewObject(gdk_env, int_class, new_int, (jint)data);
+ MAYBE_RETHROW(gdk_env, "cannot create an Integer");
+
+ lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.ThreadLocal");
+ MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal");
+
+ set_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "set", "(Ljava/lang/Object;)V");
+ MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal.<set>");
+
+ (*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)private, set_mth, lcl_obj);
+ MAYBE_RETHROW(gdk_env, "cannot set thread local value");
}
+
+/************************************************************************/
+/* GLIB interface */
+/************************************************************************/
+
+/* set of function pointers to give to glib. */
GThreadFunctions g_thread_jni_functions =
{
g_mutex_new_jni_impl, /* mutex_new */
@@ -163,7 +477,7 @@ GThreadFunctions g_thread_jni_functions =
g_private_set_jni_impl /* private_set */
};
-void
-gdk_threads_wake ()
-{
+/* ??? */
+void gdk_threads_wake () {
+
}
diff --git a/native/jni/gtk-peer/gthread-jni.h b/native/jni/gtk-peer/gthread-jni.h
index 0bb5a56f1..a0d093dcc 100644
--- a/native/jni/gtk-peer/gthread-jni.h
+++ b/native/jni/gtk-peer/gthread-jni.h
@@ -43,5 +43,6 @@ exception statement from your version. */
#include "gtkpeer.h"
extern GThreadFunctions g_thread_jni_functions;
+extern JavaVM *gdk_vm;
#endif /* __GTHREADJNI_H__ */