From bfc442fc817ea30438cad6117f770aab76f662e3 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Tue, 3 Apr 2007 19:33:45 +0000 Subject: 2007-04-03 Roman Kennke * gnu/java/awt/peer/gtk/GThreadMutex.java, * gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java, * include/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h, * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c, * native/jni/gtk-peer/gthread-jni.c, * native/jni/gtk-peer/gthread-jni.h: Removed. * native/jni/gtk-peer/Makefile.am: Removed obsolete entries for removed files. * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c Removed unused bits from gthread-jni.c. --- ChangeLog | 13 + gnu/java/awt/peer/gtk/GThreadMutex.java | 109 - .../awt/peer/gtk/GThreadNativeMethodRunner.java | 303 --- ...u_java_awt_peer_gtk_GThreadNativeMethodRunner.h | 19 - native/jni/gtk-peer/Makefile.am | 3 - ...u_java_awt_peer_gtk_GThreadNativeMethodRunner.c | 70 - .../gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c | 8 +- native/jni/gtk-peer/gthread-jni.c | 2592 -------------------- native/jni/gtk-peer/gthread-jni.h | 48 - 9 files changed, 16 insertions(+), 3149 deletions(-) delete mode 100644 gnu/java/awt/peer/gtk/GThreadMutex.java delete mode 100644 gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java delete mode 100644 include/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h delete mode 100644 native/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c delete mode 100644 native/jni/gtk-peer/gthread-jni.c delete mode 100644 native/jni/gtk-peer/gthread-jni.h diff --git a/ChangeLog b/ChangeLog index a2012694b..53c3644ca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2007-04-03 Roman Kennke + + * gnu/java/awt/peer/gtk/GThreadMutex.java, + * gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java, + * include/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h, + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c, + * native/jni/gtk-peer/gthread-jni.c, + * native/jni/gtk-peer/gthread-jni.h: Removed. + * native/jni/gtk-peer/Makefile.am: Removed obsolete entries + for removed files. + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c + Removed unused bits from gthread-jni.c. + 2007-04-03 Francis Kung * gnu/java/awt/peer/gtk/FreetypeGlyphVector.java diff --git a/gnu/java/awt/peer/gtk/GThreadMutex.java b/gnu/java/awt/peer/gtk/GThreadMutex.java deleted file mode 100644 index e73df9e55..000000000 --- a/gnu/java/awt/peer/gtk/GThreadMutex.java +++ /dev/null @@ -1,109 +0,0 @@ -/* GThreadMutex.java -- Implements a mutex object for glib's gthread - abstraction, for use with GNU Classpath's --portable-native-sync option. - This is used in gthread-jni.c - - Copyright (C) 2004 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -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. */ - -package gnu.java.awt.peer.gtk; - -/** Implements a mutex object for glib's gthread - abstraction, for use with GNU Classpath's --portable-native-sync option. - This is used in gthread-jni.c. - - We use this object to implement the POSIX semantics for Mutexes. They are - needed are needed for the function vector that is passed to glib's - g_thread subpackage's initialization function. - - The GThreadMutex object itself serves as the Real Lock; if code has - entered the monitor for this GThreadMutex object (in Java language, if - it's synchronized on this object) then it holds the lock that this object - represents. - - @author Steven Augart - May, 2004 - - -*/ - -class GThreadMutex -{ - /** Might "lock" be locked? Is anyone waiting - to get that lock? How long is the queue? - - If zero, nobody holds a lock on this GThreadMutex object, and nobody is - trying to get one. Before someone attempts to acquire a lock on this - object, they must increment potentialLockers. After they release their - lock on this object, they must decrement potentialLockers. - - Access to this field is guarded by synchronizing on the object - lockForPotentialLockers. - - After construction, we only access this field via JNI. - */ - volatile int potentialLockers; - - /** An object to synchronize to if you want to examine or modify the - potentialLockers field. Only hold this lock for brief - moments, just long enough to check or set the value of - lockForPotentialLockers. - - We use this representation so that g_thread_mutex_trylock() will work - with the POSIX semantics. This is the only case in which you ever hold a - lock on lockForPotentialLockers while trying to get another - lock -- if you are the mutex_trylock() implementation, and you have just - checked that potentialLockers has the value zero. In that - case, mutex_trylock() holds the lock on lockForPotentialLockers so that - another thread calling mutex_trylock() or mutex_lock() won't increment - potentialLockers after we've checked it and before we've gained the lock - on the POSIX mutex. Of course, in that case the operation of gaining - the POSIX lock itself will succeed immediately, and once it has - succeeded, trylock releases lockForPotentialLockers right away, - incremented to 1 (one). - - After construction, we only access this field via JNI. - */ - Object lockForPotentialLockers; - - GThreadMutex() - { - potentialLockers = 0; - lockForPotentialLockers = new Object(); - } -} -// Local Variables: -// c-file-style: "gnu" -// End: diff --git a/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java b/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java deleted file mode 100644 index 9a1b8e3a3..000000000 --- a/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java +++ /dev/null @@ -1,303 +0,0 @@ -/* GThreadNativeMethodRunner.java -- Implements pthread_create(), under - glib's gthread abstraction, for use with GNU Classpath's - --portable-native-sync option. - This is used by gthread-jni.c - - Copyright (C) 2004, 2005 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -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. */ - -package gnu.java.awt.peer.gtk; - -import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -/** Implements pthread_create(), under glib's gthread abstraction, for use - with GNU Classpath's --portable-native-sync option. This is used in - gthread-jni.c - - Also implements a registry for threads, mapping Thread objects to small - integers. The registry uses weak references for threads that aren't - joinable, so that they will be garbage collected. - - There are a number of possible alternative implementations. - - - The rest of this comment consists of an answer to a question that was - raised on the commit-classpath mailing list: - - Mark Wielaard wrote: - - > Can't we assume that jobject and gpointer are both (void *) so we don't - > need the int <-> Thread (global jobject ref) mapping? - > Maybe there are platforms where jobject and gpointer aren't the same, - > but I guess that is pretty unlikely. - - - I agree with you on the pointer size issues. A gpointer is a void *, so - it's certainly guaranteed to be at least as large as any other - pointer. And a jobject is implicitly an opaque pointer (in Jikes RVM, we - use small integers, but we coerce them into the representation of a - pointer). - - The int <==> Thread mapping addresses a different issue. I realize that I - did not document this properly (two and a half lines in thread_create), - and the point is subtle (at least to me; took me a while to figure out). - - The int => Thread mapping always returns jobjects that are local - references, not global ones. This is because Thread objects need to be - able to go away and be garbage collected after the thread they refer to - has died. - - If we keep a global object reference to a thread, then when do we delete - that global object reference? We have an answer in the case of GThread - objects that were explicitly created with the joinable attribute. It is - safe for us to maintain a global reference to any joinable thread, since - the joinable thread must linger (even if only in a zombie state) - until it's explicitly joined via a g_thread_join() call. The global ref - could be cleaned up at that point too. - - However, in the case of GThreads that were created non-joinable by - g_thread_create(), and in the case of Java threads that were created - within pure Java code (not via g_thread_create()), we don't want them to - linger forever, and there is no way to tell when the last reference - to such threads needs to expire. In the case of this application -- AWT - with GTK peers -- it would probably be safe anyway, since there are not - very many threads we create, but I was going for correctness even in the - case of long-running programs that might set up and tear down AWT - interfaces many times. - - So, I duplicated the POSIX thread-ID semantics. The thread ID of a - non-joinable thread remains valid as long as that thread is still alive. - Once that thread dies, the old thread ID may be reused at any moment. And - that's why the array indexed by thread ID numbers is an array of weak - references. - - That's also why the int => Thread jobject mapping function always returns - local references, since global references would lock the Thread in memory - forever. - - I would dearly love there to be a cleaner solution. I dislike the - repeated dips from C code into Java that are necessary to look up thread - ID numbers. If anyone can think of one, I'm all ears. -*/ - -class GThreadNativeMethodRunner - extends Thread -{ - /** The C function pointer that was passed to g_thread_create(). - Specifically, this the numeric address of an object of - C type "void *(*funcPtr)(void *funcArg)". - */ - private final long funcPtr; - - /** The argument for the function "funcPtr(funcArg)". */ - private final long funcArg; - - GThreadNativeMethodRunner(long funcPtr, long funcArg, boolean joinable) - { - this.funcPtr = funcPtr; - this.funcArg = funcArg; - - if (joinable) - registerSelfJoinable(); - } - - public void run() - { - nativeRun(funcPtr, funcArg); - } - - private native void nativeRun(long funcPtr, long funcArg); - - /** THREADS is an array of threads, indexed by thread ID codes. Not sure - whether this is the "best" approach but it does make it O(1) to look up a - thread by its ID. - - Zero is a valid thread ID code. Any negative number is invalid. - - Possible future fixes (TODO?) - - - The THREADS array will only grow. probably not a problem. - But we could keep count when nulling entries and shrink when we have - lots of nulls at the end. Probably not worth it. --mjw - - - Could make this a set of Object; see the comment on "joinable" below. - - The initial size of 17 is just a starting point. Any number will do, - including zero. - */ - private static WeakReference[] threads = new WeakReference[17]; - - /** Used by threadToThreadID, below. Returns the registration number of - the newly-registered thread. - */ - private static synchronized int registerThread(Thread t) - { - int i; - - for (i = 0; i < threads.length; ++i) - { - WeakReference ref = threads[i]; - if (ref == null) - break; // found an empty spot. - } - - if (i == threads.length) - { - /* expand the array */ - WeakReference[] bigger = new WeakReference[threads.length * 2]; - System.arraycopy(threads, 0, bigger, 0, threads.length); - threads = bigger; - } - - threads[i] = new WeakReference(t); - - return i; - } - - /** Look up the Thread ID # for a Thread. Assign a Thread ID # if none - exists. This is a general routine for handling all threads, including - the VM's main thread, if appropriate. - - - Runs in O(n/2) time. - - We can't just issue a threadID upon thread creation. If we were to do - that, not all threads would have a threadID, because not all threads - are launched by GThreadNativeMethodRunner. - */ - static synchronized int threadToThreadID(Thread t) - { - for (int i = 0; i < threads.length; ++i ) - { - if (threads[i] == null) - continue; - Thread referent = (Thread) threads[i].get(); - if (referent == null) - { - threads[i] = null; // Purge the dead WeakReference. - continue; - } - if (referent.equals(t)) - return i; - } // for() - - /* No match found. */ - return registerThread(t); - } - - /** @param threadID Must be a non-negative integer. - - Used to return null if the thread number was out of range or if - the thread was unregistered. Now we throw an exception. - - Possible Alternative Interface: We could go back to returning null in - some sort of check-free mode, so code that calls this function must - be prepared to get null. - */ - static Thread threadIDToThread(int threadID) - throws IllegalArgumentException - { - if (threadID < 0) - throw new IllegalArgumentException("Received a negative threadID, " - + threadID); - if (threadID >= threads.length) - throw new IllegalArgumentException("Received a threadID (" + threadID - + ") higher than was" - + " ever issued"); - - /* Note: if the user is using a stale reference, things will just - break. We might end up getting a different thread than the one - expected. - - TODO: Add an error-checking mode where the user's problems with threads - are announced. For instance, if the user asks for the thread - associated with a threadID that was never issued, we could print a - warning or even abort. - - TODO: Consider optionally disabling all of the error-checking we - already have; it probably slows down the implementation. We could - just return NULL. This is just the reverse of the above TODO item. - */ - - WeakReference threadRef = threads[threadID]; - - if (threadRef == null) - throw new IllegalArgumentException("Asked to look up a stale or unissued" - + "threadID (" + threadID + ")" ); - - - Thread referent = (Thread) threadRef.get(); - if (referent == null) - throw new IllegalArgumentException ("Asked to look up a stale threadID (" - + threadID + ")"); - return referent; - } - - /** Joinable threads need a hard reference, so that they won't go away when - they die. That is because their thread IDs need to stay valid until the - thread is joined via thread_join(threadID). Joinable threads have to be - explicitly joined before they are allowed to go away completely. - - Possible Alternative Implementation: Eliminate the Joinable set. When - calling getThreadIDFromThread() you know whether or not the thread - is joinable. So just store the Thread itself in the threads array? - Make that array an Object array and check with instanceof. This - looks cleaner and more robust to me and it saves a native -> Java - call. But instanceof might be expensive. --mjw - */ - private static final Set joinable = - Collections.synchronizedSet(new HashSet()); - - /** Only called from the constructor. */ - private void registerSelfJoinable() - { - joinable.add(this); - } - - /** This method is only called from JNI, and only after we have succeeded in - a thread_join() operation. */ - static void deRegisterJoinable(Thread thread) - { - joinable.remove(thread); - } -} - -// Local Variables: -// c-file-style: "gnu" -// End: diff --git a/include/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h b/include/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h deleted file mode 100644 index 1db809878..000000000 --- a/include/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h +++ /dev/null @@ -1,19 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ - -#ifndef __gnu_java_awt_peer_gtk_GThreadNativeMethodRunner__ -#define __gnu_java_awt_peer_gtk_GThreadNativeMethodRunner__ - -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_nativeRun (JNIEnv *env, jobject, jlong, jlong); - -#ifdef __cplusplus -} -#endif - -#endif /* __gnu_java_awt_peer_gtk_GThreadNativeMethodRunner__ */ diff --git a/native/jni/gtk-peer/Makefile.am b/native/jni/gtk-peer/Makefile.am index b7e84144e..3084c97e4 100644 --- a/native/jni/gtk-peer/Makefile.am +++ b/native/jni/gtk-peer/Makefile.am @@ -6,7 +6,6 @@ libgtkpeer_la_SOURCES = gnu_java_awt_peer_gtk_CairoSurface.c \ gnu_java_awt_peer_gtk_ComponentGraphics.c \ gnu_java_awt_peer_gtk_ComponentGraphicsCopy.c \ gnu_java_awt_peer_gtk_FreetypeGlyphVector.c \ - gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c \ gnu_java_awt_peer_gtk_GdkFontPeer.c \ gnu_java_awt_peer_gtk_GdkGraphicsEnvironment.c \ gnu_java_awt_peer_gtk_GdkPixbufDecoder.c \ @@ -42,10 +41,8 @@ libgtkpeer_la_SOURCES = gnu_java_awt_peer_gtk_CairoSurface.c \ gnu_java_awt_peer_gtk_GtkVolatileImage.c \ GtkDragSourceContextPeer.c \ cairographics2d.h \ - gthread-jni.c \ gdkdisplay.h \ gdkfont.h \ - gthread-jni.h \ gtk_jawt.c \ gtkpeer.h diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c deleted file mode 100644 index 595c1a28a..000000000 --- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c +++ /dev/null @@ -1,70 +0,0 @@ -/* Native implementation of functions in GThreadNativeMethodRunner - Copyright (C) 2004 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -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. */ - - -#include "gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h" -#include "gthread-jni.h" - -/* - * Class: GThreadNativeMethodRunner - * Method: nativeRun - * Signature: (J)V - * - * Purpose: Run the C function whose function pointer is - * - */ -JNIEXPORT void JNICALL -Java_gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_nativeRun - (JNIEnv *env __attribute__((unused)), - jobject lcl_obj __attribute__((unused)), - jlong funcAddr, jlong funcArg) -{ - /* Convert the function's address back into a pointer to a C function. */ - void *(*funcPtr)(void *) = (void *(*)(void *)) (size_t)funcAddr; - - /* We do not need to worry about the return value from funcPtr(); it's - just thrown away. That is part of the g_threads spec, so no reason - to worry about returning it. */ - (void) funcPtr((void *) (size_t)funcArg); - /* Fall off the end and terminate the thread of control. */ -} - -/* Local Variables: */ -/* c-file-style: "gnu" */ -/* End: */ - - diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c index 7629a26e3..5d73af4e6 100644 --- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c +++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c @@ -39,7 +39,6 @@ exception statement from your version. */ #include "gtkpeer.h" #include "gnu_java_awt_peer_gtk_GtkToolkit.h" -#include "gthread-jni.h" #include "jcl.h" #include @@ -114,7 +113,7 @@ double cp_gtk_dpi_conversion_factor; static void jni_lock_cb(); static void jni_unlock_cb(); -static void init_glib_threads(JNIEnv *, jint, jobject); +static void init_glib_threads(jint, jobject); static gboolean post_set_running_flag (gpointer); static gboolean set_running_flag (gpointer); static gboolean clear_running_flag (gpointer); @@ -170,7 +169,7 @@ Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkInit (JNIEnv *env, argv[0][0] = '\0'; argv[1] = NULL; - init_glib_threads(env, portableNativeSync, lock); + init_glib_threads(portableNativeSync, lock); /* From GDK 2.0 onwards we have to explicitly call gdk_threads_init */ gdk_threads_init(); @@ -257,7 +256,7 @@ static void jni_unlock_cb() In some release following 0.10, that config.h macro will go away.) */ static void -init_glib_threads(JNIEnv *env, jint portableNativeSync, jobject lock) +init_glib_threads(jint portableNativeSync, jobject lock) { if (portableNativeSync < 0) { @@ -269,7 +268,6 @@ init_glib_threads(JNIEnv *env, jint portableNativeSync, jobject lock) #endif } - (*env)->GetJavaVM( env, &cp_gtk_the_vm ); if (!g_thread_supported ()) { if (portableNativeSync) diff --git a/native/jni/gtk-peer/gthread-jni.c b/native/jni/gtk-peer/gthread-jni.c deleted file mode 100644 index 384ad0db6..000000000 --- a/native/jni/gtk-peer/gthread-jni.c +++ /dev/null @@ -1,2592 +0,0 @@ -/* gthread-jni.c -- JNI threading routines for GLIB - Copyright (C) 1998, 2004 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -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 */ -/************************************************************************/ - -/* - * @author Julian Dolby (dolby@us.ibm.com) - * @date February 7, 2003 implemented for GLIB v.1 - * - * - * @author Steven Augart - * , - * @date April 30, 2004 -- May 10 2004: Support new functions for Glib v.2, - * fix cond_wait to free and re-acquire the mutex, - * replaced trylock stub implementation with a full one. - * - * 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 functionality uses the java.lang.ThreadLocal class. - * - * Classpath's AWT support uses GTK+ peers. GTK+ uses GLIB. GLIB by default - * uses the platform's native threading model -- pthreads in most cases. If - * the Java runtime doesn't use the native threading model, then it needs this - * code in order to use Classpath's (GTK+-based) AWT routines. - * - * This code should be portable; I believe it makes no assumptions - * about the underlying VM beyond that it implements the JNI functionality - * that this code uses. - * - * Currently, use of this code is governed by the configuration option - * --enable-portable-native-sync. We will soon add a VM hook so the VM can - * select which threading model it wants to use at run time; at that point, - * the configuration option will go away. - * - * The code in this file uses only JNI 1.1, except for one JNI 1.2 function: - * GetEnv, in the JNI Invocation API. (There seems to be no way around using - * GetEnv). - * - * ACKNOWLEDGEMENT: - * - * I would like to thank Mark Wielaard for his kindness in spending at least - * six hours of his own time in reviewing this code and correcting my GNU - * coding and commenting style. --Steve Augart - * - * - * NOTES: - * - * This code has been tested with Jikes RVM and with Kaffe. - * - * This code should have proper automated unit tests. I manually tested it - * by running an application that uses AWT. --Steven Augart - * - * MINOR NIT: - * - * - Using a jboolean in the arglist to "throw()" and "rethrow()" - * triggers many warnings from GCC's -Wconversion operation, because that - * is not the same as the conversion (upcast to an int) that would occur in - * the absence of a prototype. - * - * It would be very slightly more efficient to just pass the jboolean, but - * is not worth the clutter of messages. The right solution would be to - * turn off the -Wconversion warning for just this file, *except* that - * -Wconversion also warns you against constructs such as: - * unsigned u = -1; - * and that is a useful warning. So I went from a "jboolean" to a - * "gboolean" (-Wconversion is not enabled by default for GNU Classpath, - * but it is in my own CFLAGS, which, for gcc 3.3.3, read: -pipe -ggdb3 -W - * -Wall -Wbad-function-cast -Wcast-align -Wpointer-arith -Wcast-qual - * -Wshadow -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations - * -fkeep-static-consts -fkeep-inline-functions -Wundef -Wwrite-strings - * -Wno-aggregate-return -Wmissing-noreturn -Wnested-externs -Wtrigraphs - * -Wconversion -Wsign-compare -Wno-float-equal -Wmissing-format-attribute - * -Wno-unreachable-code -Wdisabled-optimization ) - */ - -#include - -/************************************************************************/ -/* Configuration */ -/************************************************************************/ - -/** Tracing and Reporting **/ -#define TRACE_API_CALLS 0 /* announce entry and exit into each method, - by printing to stderr. */ - -#define TRACE_MONITORS 0 /* Every enterMonitor() and exitMonitor() goes - to stderr. */ - -/** Trouble handling. There is a discussion below of this. **/ -#define EXPLAIN_TROUBLE 1 /* Describe any unexpected trouble that - happens. This is a superset - of EXPLAIN_BROKEN, and if set trumps an - unset EXPLAIN_BROKEN. It is not a strict - superset, since at the moment there is no - TROUBLE that is not also BROKEN. - - Use criticalMsg() to describe the problem. - */ - -#define EXPLAIN_BROKEN 1 /* Describe trouble that is serious enough to - be BROKEN. (Right now all trouble is at - least BROKEN.) */ - -/* There is no EXPLAIN_BADLY_BROKEN definition. We always explain - BADLY_BROKEN trouble, since there is no other way to report it. */ - - -/** Error Handling **/ -#define DIE_IF_BROKEN 1 /* Dies if serious trouble happens. There is - really no non-serious trouble, except - possibly problems that arise during - pthread_create, which are reported by a - GError. - - If you do not set DIE_IF_BROKEN, then - trouble will raise a Java RuntimeException. - We probably do want to die right away, - since anything that's BROKEN really - indicates a programming error or a - system-wide error, and that's what the glib - documentation says you should do in case of - that kind of error in a glib-style - function. But it does work to turn this - off. */ - -#if DIE_IF_BROKEN -#define DIE_IF_BADLY_BROKEN 1 /* DIE_IF_BROKEN implies DIE_IF_BADLY_BROKEN */ -#else -#define DIE_IF_BADLY_BROKEN 1 /* Die if the system is badly broken -- - that is, if we have further trouble while - attempting to throw an exception - upwards, or if we are unable to generate - one of the classes we'll need in order to - throw wrapped exceptions upward. - - If unset, we will print a warning message, - and limp along anyway. Not that the system - is likely to work. */ -#endif - -/** Performance tuning parameters **/ - -#define ENABLE_EXPENSIVE_ASSERTIONS 0 /* Enable expensive assertions? */ - -#define DELETE_LOCAL_REFS 1 /* Whether to delete local references. - - JNI only guarantees that there wil be 16 - available. (Jikes RVM provides an number - only limited by VM memory.) - - Jikes RVM will probably perform faster if - this is turned off, but other VMs may need - this to be turned on in order to perform at - all, or might need it if things change. - - Remember, we don't know how many of those - local refs might have already been used up - by higher layers of JNI code that end up - calling g_thread_self(), - g_thread_set_private(), and so on. - - We set this to 1 for GNU Classpath, since - one of our principles is "always go for the - most robust implementation" */ - -#define HAVE_JNI_VERSION_1_2 0 /* Assume we don't. We could - dynamically check for this. We will - assume JNI 1.2 in later versions of - Classpath. - - As it stands, the code in this file - already needs one JNI 1.2 function: - GetEnv, in the JNI Invocation API. - - TODO This code hasn't been tested yet. - And really hasn't been implemented yet. - */ - -/************************************************************************/ -/* Global data */ -/************************************************************************/ - -#if defined HAVE_STDINT_H -#include /* provides intptr_t */ -#elif defined HAVE_INTTYPES_H -#include -#endif -#include /* va_list */ -#include -#include "gthread-jni.h" -#include /* assert() */ - -/* For Java thread priority constants. */ -#include - -/* Since not all JNI header generators actually define constants we - define them here explicitly. */ -#ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MIN_PRIORITY -#define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MIN_PRIORITY 1 -#endif -#ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY -#define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY 5 -#endif -#ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY -#define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY 10 -#endif - -/* The VM handle. This is set in - Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit */ -JavaVM *cp_gtk_the_vm; - -/* Unions used for type punning. */ -union env_union -{ - void **void_env; - JNIEnv **jni_env; -}; - -union func_union -{ - void *void_func; - GThreadFunc g_func; -}; - -/* Forward Declarations for Functions */ -static int threadObj_set_priority (JNIEnv * env, jobject threadObj, - GThreadPriority gpriority); -static void fatalMsg (const char fmt[], ...) - __attribute__ ((format (printf, 1, 2))) - __attribute__ ((noreturn)); - -static void criticalMsg (const char fmt[], ...) - __attribute__ ((format (printf, 1, 2))); - -static void tracing (const char fmt[], ...) - __attribute__ ((format (printf, 1, 2))); - -static jint javaPriorityLevel (GThreadPriority priority) - __attribute__ ((const)); - -/************************************************************************/ -/* Trouble-handling, including utilities to reflect exceptions */ -/* back to the VM. Also some status reporting. */ -/************************************************************************/ - -/* How are we going to handle problems? - - There are several approaches: - - 1) Report them with the GError mechanism. - - (*thread_create)() is the only one of these functions that takes a - GError pointer. And the only G_THREAD error defined maps onto EAGAIN. - We don't have any errors in our (*thread_create)() implementation that - can be mapped to EAGAIN. So this idea is a non-starter. - - 2) Reflect the exception back to the VM, wrapped in a RuntimeException. - This will fail sometimes, if we're so broken (BADLY_BROKEN) that we - fail to throw the exception. - - 3) Abort execution. This is what the glib functions themselves do for - errors that they can't report via GError. - - Enable DIE_IF_BROKEN and/or DIE_IF_BADLY_BROKEN to - make this the default for BROKEN and/or BADLY_BROKEN trouble. - - 4) Display messages to stderr. We always do this for BADLY_BROKEN - trouble. The glib functions do that for errors they can't report via - GError. - - There are some complications. - - When I attempted to report a problem in g_thread_self() using g_critical (a - macro around g_log(), I found that g_log in turn looks for thread-private - data and calls g_thread_self() again. - - We got a segfault, probably due to stack overflow. So, this code doesn't - use the g_critical() and g_error() functions any more. Nor do we use - g_assert(); we use the C library's assert() instead. -*/ - - -#define WHERE __FILE__ ":" G_STRINGIFY(__LINE__) ": " - -/* This is portable to older compilers that lack variable-argument macros. - This used to be just g_critical(), but then we ran into the error reporting - problem discussed above. -*/ -static void -fatalMsg (const char fmt[], ...) -{ - va_list ap; - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - fputs ("\nAborting execution\n", stderr); - abort (); -} - - -static void -criticalMsg (const char fmt[], ...) -{ - va_list ap; - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - putc ('\n', stderr); -} - -/* Unlike the other two, this one does not append a newline. This is only - used if one of the TRACE_ macros is defined. */ -static void -tracing (const char fmt[], ...) -{ - va_list ap; - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); -} - -#define assert_not_reached() \ - do \ - { \ - fputs(WHERE "You should never get here. Aborting execution.\n", \ - stderr); \ - abort(); \ - } \ - while(0) - - -#if DIE_IF_BADLY_BROKEN -#define BADLY_BROKEN fatalMsg -#else -#define BADLY_BROKEN criticalMsg -/* So, the user may still attempt to recover, even though we do not advise - this. */ -#endif - -/* I find it so depressing to have to use C without varargs macros. */ -#define BADLY_BROKEN_MSG WHERE "Something fundamental" \ - " to GNU Classpath's AWT JNI broke while we were trying to pass up a Java error message" - -#define BADLY_BROKEN0() \ - BADLY_BROKEN(BADLY_BROKEN_MSG); -#define BADLY_BROKEN1(msg) \ - BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg) -#define BADLY_BROKEN2(msg, arg) \ - BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg, arg) -#define BADLY_BROKEN3(msg, arg, arg2) \ - BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg, arg1, arg2) -#define BADLY_BROKEN4(msg, arg, arg2, arg3) \ - BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg, arg1, arg2, arg3) - -#define DELETE_LOCAL_REF(env, ref) \ - do \ - { \ - if ( DELETE_LOCAL_REFS ) \ - { \ - (*env)->DeleteLocalRef (env, ref); \ - (ref) = NULL; \ - } \ - } \ - while(0) - -/* Cached info for Exception-wrapping */ - -static jclass runtimeException_class; /* java.lang.RuntimeException */ -static jmethodID runtimeException_ctor; /* constructor for it */ - - -/* Throw a new RuntimeException. It may wrap around an existing exception. - 1 if we did rethrow, -1 if we had trouble while rethrowing. - isBroken is always true in this case. */ -static int -throw (JNIEnv * env, jthrowable cause, const char *message, - gboolean isBroken, const char *file, int line) -{ - jstring jmessage; - gboolean describedException = FALSE; /* Did we already describe the - exception to stderr or the - equivalent? */ - jthrowable wrapper; - - /* allocate local message in Java */ - const char fmt[] = "In AWT JNI, %s (at %s:%d)"; - size_t len = strlen (message) + strlen (file) + sizeof fmt + 25; - char *buf; - - if (EXPLAIN_TROUBLE || (isBroken && EXPLAIN_BROKEN)) - { - criticalMsg ("%s:%d: AWT JNI failure%s: %s\n", file, line, - isBroken ? " (BROKEN)" : "", message); - if (cause) - { - jthrowable currentException = (*env)->ExceptionOccurred (env); - - if (cause == currentException) - { - criticalMsg ("Description follows to System.err:"); - (*env)->ExceptionDescribe (env); - /* ExceptionDescribe has the side-effect of clearing the pending - exception; relaunch it. */ - describedException = TRUE; - - if ((*env)->Throw (env, cause)) - { - BADLY_BROKEN1 - ("Relaunching an exception with Throw failed."); - return -1; - } - } - else - { - DELETE_LOCAL_REF (env, currentException); - criticalMsg (WHERE - "currentException != cause; something else happened" - " while handling an exception."); - } - } - } /* if (EXPLAIN_TROUBLE) */ - - if (isBroken && DIE_IF_BROKEN) - fatalMsg ("%s:%d: Aborting execution; BROKEN: %s\n", file, line, message); - - if ((buf = malloc (len))) - { - memset (buf, 0, len); - g_snprintf (buf, len, fmt, message, file, line); - jmessage = (*env)->NewStringUTF (env, buf); - free (buf); - } - else - { - jmessage = NULL; - } - - /* Create the RuntimeException wrapper object and throw it. It is OK for - CAUSE to be NULL. */ - wrapper = (jthrowable) (*env)->NewObject - (env, runtimeException_class, runtimeException_ctor, jmessage, cause); - DELETE_LOCAL_REF (env, jmessage); - - if (!wrapper) - { - /* I think this should only happen: - - if there are bugs in my JNI code, or - - if the VM is broken, or - - if we run out of memory. - */ - if (EXPLAIN_TROUBLE) - { - criticalMsg (WHERE "GNU Classpath: JNI NewObject() could not create" - " a new java.lang.RuntimeException."); - criticalMsg ("We were trying to warn about the following" - " previous failure:"); - criticalMsg ("%s:%d: %s", file, line, message); - criticalMsg ("The latest (NewObject()) exception's description" - " follows, to System.err:"); - (*env)->ExceptionDescribe (env); - } - BADLY_BROKEN1 ("Failure of JNI NewObject()" - " to make a java.lang.RuntimeException"); - return -1; - } - - - /* throw it */ - if ((*env)->Throw (env, wrapper)) - { - /* Throw() should just never fail, unless we're in such severe trouble - that we might as well die. */ - BADLY_BROKEN1 - ("GNU Classpath: Failure of JNI Throw to report an Exception"); - return -1; - } - - DELETE_LOCAL_REF (env, wrapper); - return 1; -} - - - -/* Rethrow an exception we received, wrapping it with a RuntimeException. 1 - if we did rethrow, -1 if we had trouble while rethrowing. - CAUSE should be identical to the most recent exception that happened, so - that ExceptionDescribe will work. (Otherwise nix.) */ -static int -rethrow (JNIEnv * env, jthrowable cause, const char *message, - gboolean isBroken, const char *file, int line) -{ - assert (cause); - return throw (env, cause, message, isBroken, file, line); -} - - -/* 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. - * - * Returns 0 if no problems found (so no exception thrown), 1 if we rethrew an - * exception. Returns -1 on failure. - */ -static int -maybe_rethrow (JNIEnv * env, const char *message, gboolean isBroken, - const char *file, int line) -{ - jthrowable cause = (*env)->ExceptionOccurred (env); - int ret = 0; - - /* rethrow if an exception happened */ - if (cause) - { - ret = rethrow (env, cause, message, isBroken, file, line); - DELETE_LOCAL_REF (env, cause); - } - - return 0; -} - -/* MAYBE_TROUBLE() is used to include a source location in the exception - message. Once we have run maybe_rethrow, if there WAS trouble, - return TRUE, else FALSE. - - MAYBE_TROUBLE() is actually never used; all problems that throw exceptions - are BROKEN, at least. Nothing is recoverable :(. See the discussion of - possible errors at thread_create_jni_impl(). */ -#define MAYBE_TROUBLE(_env, _message) \ - maybe_rethrow(_env, _message, FALSE, __FILE__, __LINE__) - -/* MAYBE_TROUBLE(), but something would be BROKEN if it were true. */ -#define MAYBE_BROKEN(_env, _message) \ - maybe_rethrow(_env, _message, TRUE, __FILE__, __LINE__) - -/* Like MAYBE_TROUBLE(), TROUBLE() is never used. */ -#define TROUBLE(_env, _message) \ - rethrow(_env, (*env)->ExceptionOccurred (env), _message, FALSE, \ - __FILE__, __LINE__) - -#define BROKEN(_env, _message) \ - rethrow (_env, (*env)->ExceptionOccurred (env), _message, TRUE, \ - __FILE__, __LINE__) - -/* Like MAYBE_TROUBLE(), NEW_TROUBLE() is never used. */ -#define NEW_TROUBLE(_env, _message) \ - throw (_env, NULL, _message, FALSE, __FILE__, __LINE__) - -#define NEW_BROKEN(_env, _message) \ - throw (_env, NULL, _message, TRUE, __FILE__, __LINE__) - -/* Like MAYBE_TROUBLE(), RETHROW_CAUSE() is never used. */ -#define RETHROW_CAUSE(_env, _cause, _message) \ - rethrow (_env, _cause, _message, FALSE, __FILE__, __LINE__) - -#define BROKEN_CAUSE(_env, _cause, _message) \ - rethrow (_env, _cause, _message, TRUE, __FILE__, __LINE__) - -/* Macros to handle the possibility that someone might have called one of the - GThreadFunctions API functions with a Java exception pending. It is - generally discouraged to continue to use JNI after a Java exception has - been raised. Sun's JNI book advises that one trap JNI errors immediately - and not continue with an exception pending. - - These are #if'd out for these reasons: - - 1) They do not work in the C '89 subset that Classpath is currently - (2004 May 10) sticking to; HIDE_OLD_TROUBLE() includes a declaration - that should be in scope for the rest of the function, so it needs a - language version that lets you mix declarations and statements. (This - could be worked around if it were important.) - - 2) They chew up more time and resources. - - 3) There does not ever seem to be old trouble -- the assertion in - HIDE_OLD_TROUBLE never goes off. - - You will want to re-enable them if this code needs to be used in a context - where old exceptions might be pending when the GThread functions are - called. - - The implementations in this file are responsible for skipping around calls - to SHOW_OLD_TROUBLE() if they've raised exceptions during the call. So, if - we reach SHOW_OLD_TROUBLE, we are guaranteed that there are no exceptions - pending. */ -#if 1 -#define HIDE_OLD_TROUBLE(env) \ - assert ( NULL == (*env)->ExceptionOccurred (env) ) - -#define SHOW_OLD_TROUBLE() \ - assert ( NULL == (*env)->ExceptionOccurred (env) ) -#else /* 0 */ -#define HIDE_OLD_TROUBLE(env) \ - jthrowable savedTrouble = (*env)->ExceptionOccurred (env); \ - (*env)->ExceptionClear (env); - -#define SHOW_OLD_TROUBLE() do \ -{ \ - assert ( NULL == (*env)->ExceptionOccurred (env) ) \ - if (savedTrouble) \ - { \ - if ((*env)->Throw (env, savedTrouble)) \ - BADLY_BROKEN ("ReThrowing the savedTrouble failed"); \ - } \ - DELETE_LOCAL_REF (env, savedTrouble); \ -} while(0) - -#endif /* 0 */ - -/* Set up the cache of jclass and jmethodID primitives we need - in order to throw new exceptions and rethrow exceptions. We do this - independently of the other caching. We need to have this cache set up - first, so that we can then report errors properly. - - If any errors while setting up the error cache, the world is BADLY_BROKEN. - - May be called more than once. - - Returns -1 if the cache was not initialized properly, 1 if it was. -*/ -static int -setup_exception_cache (JNIEnv * env) -{ - static int exception_cache_initialized = 0; /* -1 for trouble, 1 for proper - init. */ - - jclass lcl_class; /* a class used for local refs */ - - if (exception_cache_initialized) - return exception_cache_initialized; - lcl_class = (*env)->FindClass (env, "java/lang/RuntimeException"); - if ( ! lcl_class ) - { - BADLY_BROKEN1 ("Broken Class library or VM?" - " Couldn't find java/lang/RuntimeException"); - return exception_cache_initialized = -1; - } - /* Pin it down. */ - runtimeException_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); - DELETE_LOCAL_REF (env, lcl_class); - if (!runtimeException_class) - { - BADLY_BROKEN1 ("Serious trouble: could not turn" - " java.lang.RuntimeException into a global reference"); - return exception_cache_initialized = -1; - } - - runtimeException_ctor = - (*env)->GetMethodID (env, runtimeException_class, "", - "(Ljava/lang/String;Ljava/lang/Throwable;)V"); - if ( ! runtimeException_ctor ) - { - BADLY_BROKEN1 ("Serious trouble: classpath couldn't find a" - " two-arg constructor for java/lang/RuntimeException"); - return exception_cache_initialized = -1; - } - - return exception_cache_initialized = 1; -} - - -/**********************************************************/ -/***** The main cache *************************************/ -/**********************************************************/ - -/** This is a cache of all classes, methods, and field IDs that we use during - the run. We maintain a permanent global reference to each of the classes - we cache, since otherwise the (local) jclass that refers to that class - would go out of scope and possibly be reused in further calls. - - The permanent global reference also achieves the secondary goal of - protecting the validity of the methods and field IDs in case the classes - were otherwise unloaded and then later loaded again. Obviously, this will - never happen to classes such as java.lang.Thread and java.lang.Object, but - the primary reason for maintaining permanent global refs is sitll valid. - - The code in jnilink.c has a similar objective. TODO: Consider using that - code instead. - - --Steven Augart -*/ - -/* All of these are cached classes and method IDs: */ -/* java.lang.Object */ -static jclass obj_class; /* java.lang.Object */ -static jmethodID obj_ctor; /* no-arg Constructor for java.lang.Object */ -static jmethodID obj_notify_mth; /* java.lang.Object.notify() */ -static jmethodID obj_notifyall_mth; /* java.lang.Object.notifyall() */ -static jmethodID obj_wait_mth; /* java.lang.Object.wait() */ -static jmethodID obj_wait_nanotime_mth; /* java.lang.Object.wait(JI) */ - -/* GThreadMutex and its methods */ -static jclass mutex_class; -static jmethodID mutex_ctor; -static jfieldID mutex_lockForPotentialLockers_fld; -static jfieldID mutex_potentialLockers_fld; - -/* java.lang.Thread and its methods*/ -static jclass thread_class; /* java.lang.Thread */ -static jmethodID thread_current_mth; /* Thread.currentThread() */ -static jmethodID thread_equals_mth; /* Thread.equals() */ -static jmethodID thread_join_mth; /* Thread.join() */ -static jmethodID thread_setPriority_mth; /* Thread.setPriority() */ -static jmethodID thread_stop_mth; /* Thread.stop() */ -static jmethodID thread_yield_mth; /* Thread.yield() */ - -/* java.lang.ThreadLocal and its methods */ -static jclass threadlocal_class; /* java.lang.ThreadLocal */ -static jmethodID threadlocal_ctor; /* Its constructor */ -static jmethodID threadlocal_set_mth; /* ThreadLocal.set() */ -static jmethodID threadlocal_get_mth; /* ThreadLocal.get() */ - -/* java.lang.Long and its methods */ -static jclass long_class; /* java.lang.Long */ -static jmethodID long_ctor; /* constructor for it: (J) */ -static jmethodID long_longValue_mth; /* longValue()J */ - - -/* GThreadNativeMethodRunner */ -static jclass runner_class; -static jmethodID runner_ctor; -static jmethodID runner_threadToThreadID_mth; -static jmethodID runner_threadIDToThread_mth; -static jmethodID runner_deRegisterJoinable_mth; -static jmethodID runner_start_mth; /* Inherited Thread.start() */ - - -/* java.lang.InterruptedException */ -static jclass interrupted_exception_class; - - - - -/* Returns a negative value if there was trouble during initialization. - Returns a positive value of the cache was initialized correctly. - Never returns zero. */ -static int -setup_cache (JNIEnv * env) -{ - jclass lcl_class; - static int initialized = 0; /* 1 means initialized, 0 means uninitialized, - -1 means mis-initialized */ - - if (initialized) - return initialized; - - /* make sure we can report on trouble */ - if (setup_exception_cache (env) < 0) - return initialized = -1; - -#ifdef JNI_VERSION_1_2 - if (HAVE_JNI_VERSION_1_2) - assert ( ! (*env)->ExceptionCheck (env)); - else -#endif - assert ( ! (*env)->ExceptionOccurred (env)); - - /* java.lang.Object and its methods */ - lcl_class = (*env)->FindClass (env, "java/lang/Object"); - if (!lcl_class) - { - BROKEN (env, "cannot find java.lang.Object"); - return initialized = -1; - } - - /* Pin it down. */ - obj_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); - DELETE_LOCAL_REF (env, lcl_class); - if (!obj_class) - { - BROKEN (env, "Cannot get a global reference to java.lang.Object"); - return initialized = -1; - } - - obj_ctor = (*env)->GetMethodID (env, obj_class, "", "()V"); - if (!obj_ctor) - { - BROKEN (env, "cannot find constructor for java.lang.Object"); - return initialized = -1; - } - - obj_notify_mth = (*env)->GetMethodID (env, obj_class, "notify", "()V"); - if ( ! obj_notify_mth ) - { - BROKEN (env, "cannot find java.lang.Object.notify()V"); - return initialized = -1; - } - - obj_notifyall_mth = - (*env)->GetMethodID (env, obj_class, "notifyAll", "()V"); - if ( ! obj_notifyall_mth) - { - BROKEN (env, "cannot find java.lang.Object.notifyall()V"); - return initialized = -1; - } - - obj_wait_mth = (*env)->GetMethodID (env, obj_class, "wait", "()V"); - if ( ! obj_wait_mth ) - { - BROKEN (env, "cannot find Object."); - return initialized = -1; - } - - obj_wait_nanotime_mth = - (*env)->GetMethodID (env, obj_class, "wait", "(JI)V"); - if ( ! obj_wait_nanotime_mth ) - { - BROKEN (env, "cannot find Object."); - return initialized = -1; - } - - /* GThreadMutex and its methods */ - lcl_class = (*env)->FindClass (env, "gnu/java/awt/peer/gtk/GThreadMutex"); - if ( ! lcl_class) - { - BROKEN (env, "cannot find gnu.java.awt.peer.gtk.GThreadMutex"); - return initialized = -1; - } - /* Pin it down. */ - mutex_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); - DELETE_LOCAL_REF (env, lcl_class); - if ( ! mutex_class) - { - BROKEN (env, "Cannot get a global reference to GThreadMutex"); - return initialized = -1; - } - - mutex_ctor = (*env)->GetMethodID (env, mutex_class, "", "()V"); - if ( ! mutex_ctor) - { - BROKEN (env, "cannot find zero-arg constructor for GThreadMutex"); - return initialized = -1; - } - - mutex_potentialLockers_fld = (*env)->GetFieldID - (env, mutex_class, "potentialLockers", "I"); - if ( ! mutex_class ) - { - BROKEN (env, "cannot find GThreadMutex.potentialLockers"); - return initialized = -1; - } - - if (! (mutex_lockForPotentialLockers_fld = (*env)->GetFieldID - (env, mutex_class, "lockForPotentialLockers", "Ljava/lang/Object;"))) - { - BROKEN (env, "cannot find GThreadMutex.lockForPotentialLockers"); - return initialized = -1; - } - - - /* java.lang.Thread */ - if (! (lcl_class = (*env)->FindClass (env, "java/lang/Thread"))) - { - BROKEN (env, "cannot find java.lang.Thread"); - return initialized = -1; - } - - /* Pin it down. */ - thread_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); - DELETE_LOCAL_REF (env, lcl_class); - if (!thread_class) - { - BROKEN (env, "Cannot get a global reference to java.lang.Thread"); - return initialized = -1; - } - - thread_current_mth = - (*env)->GetStaticMethodID (env, thread_class, "currentThread", - "()Ljava/lang/Thread;"); - if (!thread_current_mth) - { - BROKEN (env, "cannot find Thread.currentThread() method"); - return initialized = -1; - } - - thread_equals_mth = - (*env)->GetMethodID (env, thread_class, "equals", "(Ljava/lang/Object;)Z"); - if (!thread_equals_mth) - { - BROKEN (env, "cannot find Thread.equals() method"); - return initialized = -1; - } - - thread_join_mth = (*env)->GetMethodID (env, thread_class, "join", "()V"); - if (!thread_join_mth) - { - BROKEN (env, "cannot find Thread.join() method"); - return initialized = -1; - } - - thread_stop_mth = (*env)->GetMethodID (env, thread_class, "stop", "()V"); - if ( ! thread_stop_mth ) - { - BROKEN (env, "cannot find Thread.stop() method"); - return initialized = -1; - } - - thread_setPriority_mth = - (*env)->GetMethodID (env, thread_class, "setPriority", "(I)V"); - if ( ! thread_setPriority_mth ) - { - BROKEN (env, "cannot find Thread.setPriority() method"); - return initialized = -1; - } - - thread_yield_mth = - (*env)->GetStaticMethodID (env, thread_class, "yield", "()V"); - if ( ! thread_yield_mth ) - { - BROKEN (env, "cannot find Thread.yield() method"); - return initialized = -1; - } - - /* java.lang.ThreadLocal */ - lcl_class = (*env)->FindClass (env, "java/lang/ThreadLocal"); - if ( ! lcl_class ) - { - BROKEN (env, "cannot find class java.lang.ThreadLocal"); - return initialized = -1; - } - - /* Pin it down. */ - threadlocal_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); - DELETE_LOCAL_REF (env, lcl_class); - if ( ! threadlocal_class ) - { - BROKEN (env, "Cannot get a global reference to java.lang.ThreadLocal"); - return initialized = -1; - } - - threadlocal_ctor = (*env)->GetMethodID (env, threadlocal_class, - "", "()V"); - if ( ! threadlocal_ctor ) - { - BROKEN (env, "cannot find ThreadLocal.()V"); - return initialized = -1; - } - - threadlocal_get_mth = (*env)->GetMethodID (env, threadlocal_class, - "get", "()Ljava/lang/Object;"); - if ( ! threadlocal_get_mth ) - { - BROKEN (env, "cannot find java.lang.ThreadLocal.get()Object"); - return initialized = -1; - } - - threadlocal_set_mth = (*env)->GetMethodID (env, threadlocal_class, - "set", "(Ljava/lang/Object;)V"); - if ( ! threadlocal_set_mth ) - { - BROKEN (env, "cannot find ThreadLocal.set(Object)V"); - return initialized = -1; - } - - /* java.lang.Long */ - lcl_class = (*env)->FindClass (env, "java/lang/Long"); - if ( ! lcl_class ) - { - BROKEN (env, "cannot find class java.lang.Long"); - return initialized = -1; - } - - /* Pin it down. */ - long_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); - DELETE_LOCAL_REF (env, lcl_class); - if (!long_class) - { - BROKEN (env, "Cannot get a global reference to java.lang.Long"); - return initialized = -1; - } - - long_ctor = (*env)->GetMethodID (env, long_class, "", "(J)V"); - if (!long_ctor) - { - BROKEN (env, "cannot find method java.lang.Long.(J)V"); - return initialized = -1; - } - - long_longValue_mth = - (*env)->GetMethodID (env, long_class, "longValue", "()J"); - if (!long_longValue_mth) - { - BROKEN (env, "cannot find method java.lang.Long.longValue()J"); - return initialized = -1; - } - - - /* GThreadNativeMethodRunner */ - lcl_class = - (*env)->FindClass (env, - "gnu/java/awt/peer/gtk/GThreadNativeMethodRunner"); - if ( ! lcl_class ) - { - BROKEN (env, - "cannot find gnu.java.awt.peer.gtk.GThreadNativeMethodRunner"); - return initialized = -1; - } - - /* Pin it down. */ - runner_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); - DELETE_LOCAL_REF (env, lcl_class); - if (!runner_class) - { - BROKEN (env, - "Cannot get a global reference to the class GThreadNativeMethodRunner"); - return initialized = -1; - } - - runner_ctor = (*env)->GetMethodID (env, runner_class, "", "(JJZ)V"); - if ( ! runner_ctor ) - { - BROKEN (env, - "cannot find method GThreadNativeMethodRunner.(JJZ)"); - return initialized = -1; - } - - runner_start_mth = (*env)->GetMethodID (env, runner_class, "start", "()V"); - if ( ! runner_start_mth ) - { - BROKEN (env, "cannot find method GThreadNativeMethodRunner.start()V"); - return initialized = -1; - } - - - runner_threadToThreadID_mth = - (*env)->GetStaticMethodID (env, runner_class, - "threadToThreadID", "(Ljava/lang/Thread;)I"); - if ( ! runner_threadToThreadID_mth ) - { - BROKEN (env, - "cannot find method GThreadNativeMethodRunner.threadToThreadID(java.lang.Thread)I"); - return initialized = -1; - } - - - runner_threadIDToThread_mth = - (*env)->GetStaticMethodID (env, runner_class, - "threadIDToThread", "(I)Ljava/lang/Thread;"); - if ( ! runner_threadIDToThread_mth ) - { - BROKEN (env, - "cannot find method GThreadNativeMethodRunner.threadIDToThread(I)java.lang.Thread"); - return initialized = -1; - } - - - runner_deRegisterJoinable_mth = - (*env)->GetStaticMethodID (env, runner_class, "deRegisterJoinable", - "(Ljava/lang/Thread;)V"); - if (!runner_deRegisterJoinable_mth) - { - BROKEN (env, - "cannot find method GThreadNativeMethodRunner.deRegisterJoinable(java.lang.Thread)V"); - return initialized = -1; - } - - - /* java.lang.InterruptedException */ - lcl_class = (*env)->FindClass (env, "java/lang/InterruptedException"); - if ( ! lcl_class ) - { - BROKEN (env, "cannot find class java.lang.InterruptedException"); - return initialized = -1; - } - - /* Pin it down. */ - interrupted_exception_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); - DELETE_LOCAL_REF (env, lcl_class); - if (!interrupted_exception_class) - { - BROKEN (env, "Cannot make a global reference" - " to java.lang.InterruptedException"); - return initialized = -1; - } - -#ifdef JNI_VERSION_1_2 - if (HAVE_JNI_VERSION_1_2) - assert ( ! (*env)->ExceptionCheck (env)); - else -#endif - assert ( ! (*env)->ExceptionOccurred (env)); - - - return initialized = 1; -} - - - - - -/************************************************************************/ -/* Utilities to allocate and free java.lang.Objects */ -/************************************************************************/ - -/* 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 (JNIEnv * env) -{ - jobject lcl_obj, global_obj; - - lcl_obj = (*env)->NewObject (env, obj_class, obj_ctor); - if (!lcl_obj) - { - BROKEN (env, "cannot allocate object"); - return NULL; - } - - global_obj = (*env)->NewGlobalRef (env, lcl_obj); - DELETE_LOCAL_REF (env, lcl_obj); - if (!global_obj) - { - NEW_BROKEN (env, "cannot make global ref for a new plain Java object"); - /* Deliberate fall-through */ - } - - return global_obj; -} - -/* Frees any Java object given a global ref (isn't C fun?) */ -static void -freeObject (JNIEnv * env, jobject obj) -{ - if (obj) - { - (*env)->DeleteGlobalRef (env, obj); - /* DeleteGlobalRef can never fail */ - } -} - - -/************************************************************************/ -/* Utilities to allocate and free Java mutexes */ -/************************************************************************/ - -/* The mutexes are gnu.java.awt.peer.gtk.GThreadMutex objects, - * which this method allocates and returns a global ref. Note that global - * refs must be explicitly freed (isn't C fun?). - * - * Free this with freeObject() - */ -static jobject -allocateMutexObject (JNIEnv * env) -{ - jobject lcl_obj, global_obj; - - lcl_obj = (*env)->NewObject (env, mutex_class, mutex_ctor); - if (!lcl_obj) - { - BROKEN (env, "cannot allocate a GThreadMutex"); - return NULL; - } - - global_obj = (*env)->NewGlobalRef (env, lcl_obj); - DELETE_LOCAL_REF (env, lcl_obj); - if (!global_obj) - { - NEW_BROKEN (env, "cannot make global ref"); - /* Deliberate fallthrough */ - } - - return global_obj; -} - - -/************************************************************************/ -/* Locking code */ -/************************************************************************/ - -/* Lock a Java object */ -#define ENTER_MONITOR(env, m) \ - enterMonitor(env, m, G_STRINGIFY(m)) - -/* Return -1 on failure, 0 on success. */ -static int -enterMonitor (JNIEnv * env, jobject monitorObj, const char monName[]) -{ - if (TRACE_MONITORS) - tracing (" ", monName); - assert (monitorObj); - if ((*env)->MonitorEnter (env, monitorObj) < 0) - { - BROKEN (env, "cannot enter monitor"); - return -1; - } - return 0; -} - - -/* Unlock a Java object */ -#define EXIT_MONITOR(env, m) \ - exitMonitor(env, m, G_STRINGIFY(m)) - -static int -exitMonitor (JNIEnv * env, jobject mutexObj, const char monName[]) -{ - if (TRACE_MONITORS) - tracing (" ", monName); - assert (mutexObj); - if ((*env)->MonitorExit (env, mutexObj) < 0) - { - BROKEN (env, "cannot exit monitor "); - return -1; - } - return 0; -} - - -/************************************************************************/ -/* Miscellaneous utilities */ -/************************************************************************/ - -/* Get the Java Thread object that corresponds to a particular thread ID. - A negative thread Id gives us a null object. - - Returns a local reference. -*/ -static jobject -getThreadFromThreadID (JNIEnv * env, gpointer gThreadID) -{ - jint threadNum = GPOINTER_TO_INT(gThreadID); - jobject thread; - - if (threadNum < 0) - { - NEW_BROKEN (env, "getThreadFromThreadID asked to look up" - " a negative thread index"); - return NULL; - } - - thread = (*env)->CallStaticObjectMethod - (env, runner_class, runner_threadIDToThread_mth, threadNum); - - if (MAYBE_BROKEN (env, "cannot get Thread for threadID ")) - return NULL; - - return thread; -} - -/** Return the unique threadID of THREAD. - - Error handling: Return (gpointer) -1 on all failures, - and propagate an exception. -*/ -static gpointer -getThreadIDFromThread (JNIEnv * env, jobject thread) -{ - jint threadNum; - - if (ENABLE_EXPENSIVE_ASSERTIONS) - assert ((*env)->IsInstanceOf (env, thread, thread_class)); - - HIDE_OLD_TROUBLE (env); - - threadNum = (*env)->CallStaticIntMethod - (env, runner_class, runner_threadToThreadID_mth, thread); - - if (MAYBE_BROKEN (env, "cannot get ThreadID for a Thread ")) - { - threadNum = -1; - goto done; - } - - - SHOW_OLD_TROUBLE (); - -done: - return GINT_TO_POINTER(threadNum); -} - - -/************************************************************************/ -/* The Actual JNI functions that we pass to the function vector. */ -/************************************************************************/ - - -/************************************************************************/ -/* Mutex Functions */ -/************************************************************************/ - -/*** Mutex Utilities ****/ -struct mutexObj_cache -{ - jobject lockForPotentialLockersObj; /* Lock for the potentialLockers - field. Local reference. */ - jobject lockObj; /* The real lock we use. This is a GLOBAL - reference and must not be freed. */ -}; - -/* Initialize the cache of sub-locks for a particular mutex object. - - -1 on error, 0 on success. The caller is not responsible for freeing the - partially-populated cache in case of failure (but in practice does anyway) - (This actually never fails, though, since GetObjectField allegedly never - fails.) - - Guaranteed to leave all fields of the cache initialized, even if only to - zero. -*/ -static int -populate_mutexObj_cache (JNIEnv * env, jobject mutexObj, - struct mutexObj_cache *mcache) -{ - mcache->lockObj = mutexObj; /* the mutexObj is its own lock. */ - assert (mcache->lockObj); - - mcache->lockForPotentialLockersObj = (*env)->GetObjectField - (env, mutexObj, mutex_lockForPotentialLockers_fld); - /* GetObjectField can never fail. */ - - /* Retrieving a NULL object could only happen if we somehow got a - a mutex object that was not properly intialized. */ - assert (mcache->lockForPotentialLockersObj); - - return 0; -} - - -/* Clean out the mutexObj_cache, even if it was never populated. */ -static void -clean_mutexObj_cache (JNIEnv * env, struct mutexObj_cache *mcache) -{ - /* OK to pass NULL refs to DELETE_LOCAL_REF */ - DELETE_LOCAL_REF (env, mcache->lockForPotentialLockersObj); - /* mcache->lockObj is a GLOBAL reference. */ - mcache->lockObj = NULL; -} - -/* -1 on failure, 0 on success. - The mutexObj_cache is already populated for this particular object. */ -static int -mutexObj_lock (JNIEnv * env, jobject mutexObj, struct mutexObj_cache *mcache) -{ - jint potentialLockers; - - if (ENTER_MONITOR (env, mcache->lockForPotentialLockersObj)) - return -1; - - assert(mutexObj); - potentialLockers = - (*env)->GetIntField (env, mutexObj, mutex_potentialLockers_fld); - /* GetIntField() never fails. */ - - ++potentialLockers; - - (*env)->SetIntField - (env, mutexObj, mutex_potentialLockers_fld, potentialLockers); - - if (EXIT_MONITOR (env, mcache->lockForPotentialLockersObj)) - return -1; - - if (ENTER_MONITOR (env, mcache->lockObj)) - return -1; - - SHOW_OLD_TROUBLE (); - - return 0; -} - -/* Unlock a GMutex, once we're already in JNI and have already gotten the - mutexObj for it. This skips the messages that TRACE_API_CALLS would - print. - - Returns -1 on error, 0 on success. */ -static int -mutexObj_unlock (JNIEnv * env, jobject mutexObj, - struct mutexObj_cache *mcache) -{ - jint potentialLockers; - int ret = -1; /* assume failure until we suceed. */ - - /* Free the lock first, so that someone waiting for the lock can get it - ASAP. */ - /* This is guaranteed not to block. */ - if (EXIT_MONITOR (env, mcache->lockObj) < 0) - goto done; - - /* Kick down potentialLockers by one. We do this AFTER we free the lock, so - that we hold it no longer than necessary. */ - if (ENTER_MONITOR (env, mcache->lockForPotentialLockersObj) < 0) - goto done; - - potentialLockers = (*env)->GetIntField - (env, mutexObj, mutex_potentialLockers_fld); - /* GetIntField never fails */ - - assert (potentialLockers >= 1); - --potentialLockers; - - (*env)->SetIntField - (env, mutexObj, mutex_potentialLockers_fld, potentialLockers); - /* Never fails, so the JNI book says. */ - - /* Clean up. */ - if (EXIT_MONITOR (env, mcache->lockForPotentialLockersObj) < 0) - goto done; - ret = 0; - -done: - return ret; -} - -/*** Mutex Implementations ****/ - -/* Create a mutex, which is a java.lang.Object for us. - In case of failure, we'll return NULL. Which will implicitly - cause future calls to fail. */ -static GMutex * -mutex_new_jni_impl (void) -{ - jobject mutexObj; - JNIEnv *env; - union env_union e; - - if (TRACE_API_CALLS) - tracing ("mutex_new_jni_impl()"); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - - if (setup_cache (env) < 0) - { - mutexObj = NULL; - goto done; - } - - mutexObj = allocateMutexObject (env); - -done: - if (TRACE_API_CALLS) - tracing (" ==> %p \n", mutexObj); - - return (GMutex *) mutexObj; - -} - -/* Lock a mutex. */ -static void -mutex_lock_jni_impl (GMutex * mutex) -{ - struct mutexObj_cache mcache; - jobject mutexObj = (jobject) mutex; - JNIEnv *env; - union env_union e; - - if (TRACE_API_CALLS) - tracing ("mutex_lock_jni_impl( mutexObj = %p )", mutexObj); - - assert (mutexObj); - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - - if (setup_cache (env) < 0) - goto done; - - HIDE_OLD_TROUBLE (env); - - if (populate_mutexObj_cache (env, mutexObj, &mcache) < 0) - goto done; - - mutexObj_lock (env, mutexObj, &mcache); - /* No need to error check; we've already reported it in any case. */ - -done: - clean_mutexObj_cache (env, &mcache); - if (TRACE_API_CALLS) - tracing (" ==> VOID \n"); -} - - -/* Try to lock a mutex. Return TRUE if we succeed, FALSE if we fail. - FALSE on error. */ -static gboolean -mutex_trylock_jni_impl (GMutex * gmutex) -{ - jobject mutexObj = (jobject) gmutex; - jint potentialLockers; - gboolean ret = FALSE; - JNIEnv *env; - union env_union e; - struct mutexObj_cache mcache; - - if (TRACE_API_CALLS) - tracing ("mutex_trylock_jni_impl(mutexObj=%p)", mutexObj); - - assert (mutexObj); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - goto done; - HIDE_OLD_TROUBLE (env); - - if (populate_mutexObj_cache (env, mutexObj, &mcache) < 0) - goto done; - - if (ENTER_MONITOR (env, mcache.lockForPotentialLockersObj)) - goto done; - - potentialLockers = (*env)->GetIntField - (env, mutexObj, mutex_potentialLockers_fld); - - assert (potentialLockers >= 0); - - if (potentialLockers) - { - /* Already locked. Clean up and leave. */ - EXIT_MONITOR (env, mcache.lockForPotentialLockersObj); - /* Ignore any error code from EXIT_MONITOR; there's nothing we could do - at this level, in any case. */ - goto done; - } - - /* Guaranteed not to block. */ - if (ENTER_MONITOR (env, mcache.lockObj)) - { - /* Clean up the existing lock. */ - EXIT_MONITOR (env, mcache.lockForPotentialLockersObj); - /* Ignore any error code from EXIT_MONITOR; there's nothing we could do - at this level, in any case. */ - goto done; - } - - - /* We have the monitor. Record that fact. */ - potentialLockers = 1; - (*env)->SetIntField - (env, mutexObj, mutex_potentialLockers_fld, potentialLockers); - /* Set*Field() never fails */ - - ret = TRUE; /* We have the lock. */ - - /* Clean up. */ - if (EXIT_MONITOR (env, mcache.lockForPotentialLockersObj)) - goto done; /* If we fail at this point, still keep the - main lock. */ - - SHOW_OLD_TROUBLE (); -done: - clean_mutexObj_cache (env, &mcache); - if (TRACE_API_CALLS) - tracing (" ==> %s\n", ret ? "TRUE" : "FALSE"); - return ret; -} - - -/* Unlock a mutex. */ -static void -mutex_unlock_jni_impl (GMutex * gmutex) -{ - jobject mutexObj = (jobject) gmutex; - struct mutexObj_cache mcache; - JNIEnv *env; - union env_union e; - - if (TRACE_API_CALLS) - tracing ("mutex_unlock_jni_impl(mutexObj=%p)", mutexObj); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - goto done; - HIDE_OLD_TROUBLE (env); - - assert (mutexObj); - - if ( populate_mutexObj_cache (env, mutexObj, &mcache) < 0) - goto done; - - (void) mutexObj_unlock (env, mutexObj, &mcache); - - SHOW_OLD_TROUBLE (); - -done: - clean_mutexObj_cache (env, &mcache); - if (TRACE_API_CALLS) - tracing (" ==> VOID\n"); -} - - - -/* Free a mutex (isn't C fun?). OK this time for it to be NULL. - No failure conditions, for a change. */ -static void -mutex_free_jni_impl (GMutex * mutex) -{ - jobject mutexObj = (jobject) mutex; - JNIEnv *env; - union env_union e; - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - - if (TRACE_API_CALLS) - tracing ("mutex_free_jni_impl(%p)", mutexObj); - - freeObject (env, mutexObj); - - if (TRACE_API_CALLS) - tracing (" ==> VOID\n"); -} - - - - -/************************************************************************/ -/* Condition variable code */ -/************************************************************************/ - -/* Create a new condition variable. This is a java.lang.Object for us. */ -static GCond * -cond_new_jni_impl (void) -{ - jobject condObj; - JNIEnv *env; - union env_union e; - - if (TRACE_API_CALLS) - tracing ("mutex_free_jni_impl()"); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - - condObj = allocatePlainObject (env); - - if (TRACE_API_CALLS) - tracing (" ==> %p\n", condObj); - - return (GCond *) condObj; -} - -/* Signal on a condition variable. This is simply calling Object.notify - * for us. - */ -static void -cond_signal_jni_impl (GCond * gcond) -{ - JNIEnv *env; - union env_union e; - jobject condObj = (jobject) gcond; - - if (TRACE_API_CALLS) - tracing ("cond_signal_jni_impl(condObj = %p)", condObj); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - goto done; - HIDE_OLD_TROUBLE (env); - - assert (condObj); - - /* Must have locked an object to call notify */ - if (ENTER_MONITOR (env, condObj)) - goto done; - - (*env)->CallVoidMethod (env, condObj, obj_notify_mth); - if (MAYBE_BROKEN (env, "cannot signal mutex with Object.notify()")) - { - if (EXIT_MONITOR (env, condObj)) - BADLY_BROKEN1 ("Failed to unlock a monitor; the VM may deadlock."); - goto done; - } - - EXIT_MONITOR (env, condObj); - - SHOW_OLD_TROUBLE (); - -done: - if (TRACE_API_CALLS) - tracing (" ==> VOID\n"); -} - -/* Broadcast to all waiting on a condition variable. This is simply - * calling Object.notifyAll for us. - */ -static void -cond_broadcast_jni_impl (GCond * gcond) -{ - jobject condObj = (jobject) gcond; - JNIEnv *env; - union env_union e; - - if (TRACE_API_CALLS) - tracing ("cond_broadcast_jni_impl(condObj=%p)", condObj); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - goto done; - HIDE_OLD_TROUBLE (env); - - assert (condObj); - /* Must have locked an object to call notifyAll */ - if (ENTER_MONITOR (env, condObj)) - goto done; - - (*env)->CallVoidMethod (env, condObj, obj_notifyall_mth); - if (MAYBE_BROKEN (env, "cannot broadcast to mutex with Object.notify()")) - { - EXIT_MONITOR (env, condObj); - goto done; - } - - EXIT_MONITOR (env, condObj); - - SHOW_OLD_TROUBLE (); - -done: - if (TRACE_API_CALLS) - tracing (" ==> VOID\n"); -} - - -/* Wait on a condition variable. For us, this simply means calling - * Object.wait. - * - * Throws a Java exception on trouble; may leave the mutexes set arbitrarily. - * XXX TODO: Further improve error recovery. - */ -static void -cond_wait_jni_impl (GCond * gcond, GMutex * gmutex) -{ - struct mutexObj_cache cache; - jobject condObj = (jobject) gcond; - jobject mutexObj = (jobject) gmutex; - JNIEnv *env; - union env_union e; - - if (TRACE_API_CALLS) - tracing ("cond_wait_jni_impl(condObj=%p, mutexObj=%p)", - condObj, mutexObj); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - goto done; - HIDE_OLD_TROUBLE (env); - - assert (condObj); - assert (mutexObj); - /* Must have locked a Java object to call wait on it */ - if (ENTER_MONITOR (env, condObj) < 0) - goto done; - - /* Our atomicity is now guaranteed; we're protected by the Java monitor on - condObj. Unlock the GMutex. */ - if (mutexObj_unlock (env, mutexObj, &cache)) - goto done; - - (*env)->CallVoidMethod (env, condObj, obj_wait_mth); - if (MAYBE_BROKEN (env, "cannot wait on condObj")) - { - EXIT_MONITOR (env, condObj); /* ignore err checking */ - goto done; - } - - /* Re-acquire the lock on the GMutex. Do this while we're protected by the - Java monitor on condObj. */ - if (mutexObj_lock (env, mutexObj, &cache)) - goto done; - - EXIT_MONITOR (env, condObj); - - SHOW_OLD_TROUBLE (); - -done: - if (TRACE_API_CALLS) - tracing (" ==> VOID\n"); -} - - -/** Wait on a condition variable 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. - * - * We return FALSE if we timed out. Return TRUE if the condition was - * signalled first, before we timed out. - * - * In case of trouble we throw a Java exception. Whether we return FALSE or - * TRUE depends upon whether the condition was raised before the trouble - * happened. - * - * I believe that this function goes to the proper lengths to try to unlock - * all of the locked mutexes and monitors, as appropriate, and that it further - * tries to make sure that the thrown exception is the current one, not any - * future cascaded one from something like a failure to unlock the monitors. - */ -static gboolean -cond_timed_wait_jni_impl (GCond * gcond, GMutex * gmutex, GTimeVal * end_time) -{ - JNIEnv *env; - union env_union e; - jlong time_millisec; - jint time_nanosec; - jthrowable cause; - jobject condObj = (jobject) gcond; - jobject mutexObj = (jobject) gmutex; - gboolean condRaised = FALSE; /* Condition has not been raised yet. */ - struct mutexObj_cache cache; - gboolean interrupted; - - if (TRACE_API_CALLS) - { - tracing ("cond_timed_wait_jni_impl(cond=%p, mutex=%p," - " end_time=< sec=%lu, usec=%lu >)", condObj, mutexObj, - (unsigned long) end_time->tv_sec, - (unsigned long) end_time->tv_usec); - } - - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - goto done; - HIDE_OLD_TROUBLE (env); - - time_millisec = end_time->tv_sec * 1000 + end_time->tv_usec / 1000; - time_nanosec = 1000 * (end_time->tv_usec % 1000); - - /* Must have locked an object to call wait */ - if (ENTER_MONITOR (env, condObj) < 0) - goto done; - - if (mutexObj_unlock (env, mutexObj, &cache) < 0) - { - if (EXIT_MONITOR (env, condObj) < 0) - criticalMsg - ("Unable to unlock an existing lock on a condition; your proram may deadlock"); - goto done; - } - - - (*env)->CallVoidMethod (env, condObj, obj_wait_nanotime_mth, - time_millisec, time_nanosec); - - /* If there was trouble, save that fact, and the reason for the trouble. We - want to respond to this condition as fast as possible. */ - cause = (*env)->ExceptionOccurred (env); - - if ( ! cause ) - { - condRaised = TRUE; /* condition was signalled */ - } - else if ((*env)->IsInstanceOf (env, cause, interrupted_exception_class)) - { - condRaised = FALSE; /* Condition was not raised before timeout. - (This is redundant with the initialization - of condRaised above) */ - (*env)->ExceptionClear (env); /* Clear the InterruptedException. */ - cause = NULL; /* no pending cause now. */ - } - else - { - interrupted = FALSE; /* Trouble, but not because of - InterruptedException. Assume the condition - was not raised. */ - /* Leave condRaised set to FALSE */ - } - - /* Irrespective of whether there is a pending problem to report, go ahead - and try to clean up. This may end up throwing an exception that is - different from the one that was thrown by the call to Object.wait(). - So we will override it with the first exception (don't want to have - cascading problems). */ - if (mutexObj_lock (env, mutexObj, &cache) && !cause) - { - cause = (*env)->ExceptionOccurred (env); - assert (cause); - } - - if (EXIT_MONITOR (env, condObj) && !cause) - { - cause = (*env)->ExceptionOccurred (env); - assert (cause); - } - - if (cause) /* Raise the first cause. */ - { - BROKEN_CAUSE (env, cause, "error in timed wait or during its cleanup"); - goto done; - } - - SHOW_OLD_TROUBLE (); - -done: - if (TRACE_API_CALLS) - tracing (" ==> condRaised = %s\n", condRaised ? "TRUE" : "FALSE"); - return condRaised; -} - - -/* Free a condition variable. (isn't C fun?). Can not fail. */ -static void -cond_free_jni_impl (GCond * cond) -{ - jobject condObj = (jobject) cond; - JNIEnv *env; - union env_union e; - - if (TRACE_API_CALLS) - tracing ("cond_free_jni_impl(condObj = %p)", condObj); - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - - freeObject (env, condObj); - - if (TRACE_API_CALLS) - tracing (" ==> VOID\n"); -} - - -/************************************************************************/ -/* Thread-local data code */ -/************************************************************************/ - -/* Create a new thread-local key. We use java.lang.ThreadLocal objects - * for this. This returns the pointer representation of a Java global - * reference. - * - * We will throw a Java exception and return NULL in case of failure. - */ -static GPrivate * -private_new_jni_impl (GDestroyNotify notify __attribute__ ((unused))) -{ - JNIEnv *env; - union env_union e; - jobject lcl_key; - jobject global_key; - GPrivate *gkey = NULL; /* Error return code */ - - if (TRACE_API_CALLS) - tracing ("private_new_jni_impl()"); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - goto done; - HIDE_OLD_TROUBLE (env); - - lcl_key = (*env)->NewObject (env, threadlocal_class, threadlocal_ctor); - if ( ! lcl_key ) - { - BROKEN (env, "cannot allocate a ThreadLocal"); - goto done; - } - - global_key = ((*env)->NewGlobalRef (env, lcl_key)); - DELETE_LOCAL_REF (env, lcl_key); - if ( ! global_key) - { - NEW_BROKEN (env, "cannot create a GlobalRef to a new ThreadLocal"); - goto done; - } - - gkey = (GPrivate *) global_key; - SHOW_OLD_TROUBLE (); - -done: - if (TRACE_API_CALLS) - tracing (" ==> %p\n", (void *) gkey); - - return gkey; -} - -/* Get this thread's value for a thread-local key. This is simply - * ThreadLocal.get for us. Return NULL if no value. (I can't think of - * anything else to do.) - */ -static gpointer -private_get_jni_impl (GPrivate * gkey) -{ - JNIEnv *env; - union env_union e; - jobject val_wrapper; - jobject keyObj = (jobject) gkey; - gpointer thread_specific_data = NULL; /* Init to the error-return value */ - - jlong val; - - if (TRACE_API_CALLS) - tracing ("private_get_jni_impl(keyObj=%p)", keyObj); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - goto done; - HIDE_OLD_TROUBLE (env); - - val_wrapper = (*env)->CallObjectMethod (env, keyObj, threadlocal_get_mth); - if (MAYBE_BROKEN (env, "cannot find thread-local object")) - goto done; - - if (! val_wrapper ) - { - /* It's Java's "null" object. No ref found. This is OK; we must never - have set a value in this thread. Note that this next statement is - not necessary, strictly speaking, since we're already initialized to - NULL. A good optimizing C compiler will detect that and optimize out - this statement. */ - thread_specific_data = NULL; - goto done; - } - - val = (*env)->CallLongMethod (env, val_wrapper, long_longValue_mth); - - if (MAYBE_BROKEN (env, "cannot get thread local value")) - goto done; - - thread_specific_data = (gpointer) (intptr_t) val; - - /* Only re-raise the old pending exception if a new one hasn't come along to - supersede it. */ - SHOW_OLD_TROUBLE (); - -done: - - if (TRACE_API_CALLS) - tracing (" ==> %p\n", thread_specific_data); - - return thread_specific_data; -} - -/* Set this thread's value for a thread-local key. This is simply - * ThreadLocal.set() for us. - */ -static void -private_set_jni_impl (GPrivate * gkey, gpointer thread_specific_data) -{ - JNIEnv *env; - union env_union e; - jobject val_wrapper; - jobject keyObj = (jobject) gkey; - - - if (TRACE_API_CALLS) - tracing ("private_set_jni_impl(keyObj=%p, thread_specific_data=%p)", - keyObj, thread_specific_data); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - goto done; - HIDE_OLD_TROUBLE (env); - - /* We are just going to always use a Java long to represent a C pointer. - Otherwise all of the code would end up being conditionalized for various - pointer sizes, and that seems like too much of a hassle, in order to save - a paltry few bytes, especially given the horrendous overhead of JNI in - any case. - */ - - val_wrapper = (*env)->NewObject (env, long_class, long_ctor, - (jlong) (intptr_t) thread_specific_data); - if ( ! val_wrapper ) - { - BROKEN (env, "cannot create a java.lang.Long"); - goto done; - } - - /* At this point, we now have set lcl_obj as a numeric class that wraps - around the thread-specific data we were given. */ - (*env)->CallVoidMethod (env, keyObj, threadlocal_set_mth, val_wrapper); - if (MAYBE_BROKEN (env, "cannot set thread local value")) - goto done; - - SHOW_OLD_TROUBLE (); -done: - if (TRACE_API_CALLS) - tracing (" ==> VOID\n"); -} - - -/** Create an object of type gnu.java.awt.peer.gtk.GThreadNativeMethodRunner. - Run it. - - We need to create joinable threads. We handle the notion of a joinable - thread by determining whether or not we are going to maintain a permanent - hard reference to it until it croaks. - - Posix does not appear to have a Java-like concept of daemon threads, where - the JVM will exit when there are only daemon threads running. - - Error handling: - - To quote from the glib guide: - "GError should only be used to report recoverable runtime errors, never - to report programming errors." - - So how do we consider the failure to create a thread? Well, each of the - failure cases in this function are discussed, and none of them are really - recoverable. - - The glib library is really designed so that you should fail - catastrophically in case of "programming errors". The only error defined - for the GThread functions is G_THREAD_ERROR_AGAIN, and that for - thread_create. - - Most of these GThread functions could fail if we run out of memory, for - example, but the only one capable of reporting that fact is - thread_create. */ -static void -thread_create_jni_impl (GThreadFunc func, - gpointer data, - gulong stack_size __attribute__((unused)), - gboolean joinable, - gboolean bound __attribute__((unused)), - GThreadPriority gpriority, - /* This prototype is horrible. threadIDp is actually - a gpointer to the thread's thread-ID. Which is, - of course, itself a gpointer-typed value. Ouch. */ - gpointer threadIDp, - /* Do not touch the GError stuff unless you have - RECOVERABLE trouble. There is no recoverable - trouble in this implementation. */ - GError **errorp __attribute__((unused))) -{ - JNIEnv *env; - union env_union e; - union func_union f; - jboolean jjoinable = joinable; - jobject newThreadObj; - gpointer threadID; /* to be filled in */ - - if (TRACE_API_CALLS) - { - f.g_func = func; - tracing ("thread_create_jni_impl(func=%p, data=%p, joinable=%s," - " threadIDp=%p, *(int *) threadIDp = %d)", - f.void_func, data, joinable ? "TRUE" : "FALSE", - threadIDp, *(int *) threadIDp); - } - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - { - /* The failed call to setup the cache is certainly not recoverable; - not appropriate for G_THREAD_ERROR_AGAIN. */ - *(gpointer *) threadIDp = NULL; - goto done; - } - HIDE_OLD_TROUBLE (env); - - /* If a thread is joinable, then notify its constructor. The constructor - will enter a hard reference for it, and the hard ref. won't go away until - the thread has been joined. */ - newThreadObj = - (*env)->NewObject (env, runner_class, runner_ctor, - (jlong) (intptr_t) func, (jlong) (intptr_t) data, - jjoinable); - if ( ! newThreadObj ) - { - BROKEN (env, "creating a new thread failed in the constructor"); - *(gpointer *) threadIDp = NULL; - /* The failed call to the constructor does not throw any errors such - that G_THREAD_ERROR_AGAIN is appropriate. No other recoverable - errors defined. Once again, we go back to the VM. */ - goto done; - } - - if (threadObj_set_priority (env, newThreadObj, gpriority) < 0) - { - *(gpointer *) threadIDp = NULL; - /* None of these possible exceptions from Thread.setPriority() are - recoverable, so they are not appropriate for EAGAIN. So we should - fail. */ - goto done; - } - - (*env)->CallVoidMethod (env, runner_class, runner_start_mth); - - if (MAYBE_BROKEN (env, "starting a new thread failed")) - { - *(gpointer *) threadIDp = NULL; - /* The only exception Thread.start() throws is - IllegalStateException. And that would indicate a programming error. - - So there are no situations such that G_THREAD_ERROR_AGAIN would be - OK. - - So, we don't use g_set_error() here to perform any error reporting. - */ - goto done; - } - - threadID = getThreadIDFromThread (env, newThreadObj); - - *(gpointer *) threadIDp = threadID; - SHOW_OLD_TROUBLE (); - -done: - if (TRACE_API_CALLS) - tracing (" ==> (threadID = %p) \n", threadID); -} - - -/* Wraps a call to g_thread_yield. */ -static void -thread_yield_jni_impl (void) -{ - JNIEnv *env; - union env_union e; - - if (TRACE_API_CALLS) - tracing ("thread_yield_jni_impl()"); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - goto done; - HIDE_OLD_TROUBLE (env); - - (*env)->CallStaticVoidMethod (env, thread_class, thread_yield_mth); - if (MAYBE_BROKEN (env, "Thread.yield() failed")) - goto done; - - SHOW_OLD_TROUBLE (); - -done: - if (TRACE_API_CALLS) - tracing (" ==> VOID\n"); -} - - -static void -thread_join_jni_impl (gpointer threadID) -{ - JNIEnv *env; - union env_union e; - jobject threadObj = NULL; - - if ( TRACE_API_CALLS ) - tracing ("thread_join_jni_impl(threadID=%p) ", threadID); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - goto done; - HIDE_OLD_TROUBLE (env); - - threadObj = getThreadFromThreadID (env, threadID); - if ( ! threadObj ) /* Already reported with BROKEN */ - goto done; - - (*env)->CallVoidMethod (env, threadObj, thread_join_mth); - if (MAYBE_BROKEN (env, "Thread.join() failed")) - goto done; - - - (*env)->CallStaticVoidMethod - (env, runner_class, runner_deRegisterJoinable_mth, threadObj); - if (MAYBE_BROKEN (env, "Thread.deRegisterJoinableThread() failed")) - goto done; - - SHOW_OLD_TROUBLE (); - -done: - DELETE_LOCAL_REF (env, threadObj); - if (TRACE_API_CALLS) - tracing (" ==> VOID \n"); -} - -/* Terminate the current thread. Unlike pthread_exit(), here we do not need - to bother with a return value or exit value for the thread which is about - to croak. (The gthreads abstraction doesn't use it.) However, we *do* - need to bail immediately. We handle this with Thread.stop(), which is - a deprecated method. - - It's deprecated since we might leave objects protected by monitors in - half-constructed states on the way out -- Thread.stop() throws a - ThreadDeath exception, which is usually unchecked. There is no good - solution that I can see. */ -static void -thread_exit_jni_impl (void) -{ - JNIEnv *env; - union env_union e; - jobject this_thread; - - if (TRACE_API_CALLS) - tracing ("thread_exit_jni_impl() "); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - goto done; - - HIDE_OLD_TROUBLE (env); - - this_thread = (*env)-> - CallStaticObjectMethod (env, thread_class, thread_current_mth); - - if ( ! this_thread ) - { - BROKEN (env, "cannot get current thread"); - goto done; - } - - (*env)->CallVoidMethod (env, this_thread, thread_stop_mth); - if (MAYBE_BROKEN (env, "cannot call Thread.stop() on current thread")) - goto done; - - SHOW_OLD_TROUBLE (); - -done: - if (TRACE_API_CALLS) - tracing (" ==> VOID \n"); -} - - -/* Translate a GThreadPriority to a Java priority level. */ -static jint -javaPriorityLevel (GThreadPriority priority) -{ - /* We have these fields in java.lang.Thread to play with: - - static int MIN_PRIORITY The minimum priority that a thread can have. - static int NORM_PRIORITY The default priority that is assigned to a - thread. - static int MAX_PRIORITY The maximum priority that a thread can have. - - We get these from the header file generated by javah, even though they're - documented as being 1, 5, and 10. - */ - static const jint minJPri = - gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MIN_PRIORITY; - static const jint normJPri = - gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY; - static const jint maxJPri = - gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY; - - switch (priority) - { - case G_THREAD_PRIORITY_LOW: - return minJPri; - break; - - default: - assert_not_reached (); - /* Deliberate fall-through if assertions are turned off; also shuts up - GCC warnings if they're turned on. */ - case G_THREAD_PRIORITY_NORMAL: - return normJPri; - break; - - case G_THREAD_PRIORITY_HIGH: - return (normJPri + maxJPri) / 2; - break; - - case G_THREAD_PRIORITY_URGENT: - return maxJPri; - break; - } -} - - -/** It would be safe not to implement this, according to the JNI docs, since - not all platforms do thread priorities. However, we might as well - provide the hint for those who want it. -*/ -static void -thread_set_priority_jni_impl (gpointer gThreadID, GThreadPriority gpriority) -{ - jobject threadObj = NULL; - JNIEnv *env; - union env_union e; - - if (TRACE_API_CALLS) - tracing ("thread_set_priority_jni_impl(gThreadID=%p, gpriority = %u) ", - gThreadID, gpriority); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - - if (setup_cache (env) < 0) - goto done; - - HIDE_OLD_TROUBLE (env); - - - threadObj = getThreadFromThreadID (env, gThreadID); - if ( ! threadObj) /* Reported with BROKEN already. */ - goto done; - - if (threadObj_set_priority (env, threadObj, gpriority)) - goto done; - - SHOW_OLD_TROUBLE (); - -done: - DELETE_LOCAL_REF (env, threadObj); - - if (TRACE_API_CALLS) - tracing (" ==> VOID\n"); -} - - -/** It would be safe not to implement this, according to the JNI docs, since - not all platforms do thread priorities. However, we might as well - provide the hint for those who want it. - - -1 on failure, 0 on success. */ -static int -threadObj_set_priority (JNIEnv * env, jobject threadObj, - GThreadPriority gpriority) -{ - jint javaPriority = javaPriorityLevel (gpriority); - (*env)->CallVoidMethod (env, threadObj, thread_setPriority_mth, - javaPriority); - return MAYBE_BROKEN (env, "Thread.setPriority() failed"); -} - - -/** Return the result of Thread.currentThread(), a static method. */ -static void -thread_self_jni_impl (/* Another confusing glib prototype. This is - actually a gpointer to the thread's thread-ID. - Which is, of course, a gpointer. */ - gpointer my_thread_IDp) -{ - JNIEnv *env; - union env_union e; - jobject this_thread; - gpointer my_threadID; - - if (TRACE_API_CALLS) - tracing ("thread_self_jni_impl(my_thread_IDp=%p)", my_thread_IDp); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - - if (setup_cache (env) < 0) - return; - - HIDE_OLD_TROUBLE (env); - - this_thread = (*env)-> - CallStaticObjectMethod (env, thread_class, thread_current_mth); - if (! this_thread ) - { - BROKEN (env, "cannot get current thread"); - my_threadID = NULL; - goto done; - } - - my_threadID = getThreadIDFromThread (env, this_thread); - SHOW_OLD_TROUBLE (); - -done: - if (TRACE_API_CALLS) - tracing (" ==> (my_threadID = %p) \n", my_threadID); - - *(gpointer *) my_thread_IDp = my_threadID; -} - - -static gboolean -thread_equal_jni_impl (gpointer thread1, gpointer thread2) -{ - JNIEnv *env; - union env_union e; - - gpointer threadID1 = *(gpointer *) thread1; - gpointer threadID2 = *(gpointer *) thread2; - - jobject thread1_obj = NULL; - jobject thread2_obj = NULL; - gboolean ret; - - if (TRACE_API_CALLS) - tracing ("thread_equal_jni_impl(threadID1=%p, threadID2=%p)", - threadID1, threadID2); - - e.jni_env = &env; - (*cp_gtk_the_vm)->GetEnv (cp_gtk_the_vm, e.void_env, JNI_VERSION_1_1); - if (setup_cache (env) < 0) - { - ret = FALSE; /* what is safer? We really don't ever want - to return from here. */ - goto done; - } - - HIDE_OLD_TROUBLE (env); - thread1_obj = getThreadFromThreadID (env, threadID1); - thread2_obj = getThreadFromThreadID (env, threadID2); - - ret = (*env)->CallBooleanMethod (env, thread1_obj, - thread_equals_mth, thread2_obj); - - if (MAYBE_BROKEN (env, "Thread.equals() failed")) - { - ret = FALSE; - goto done; - } - - SHOW_OLD_TROUBLE (); - - -done: - DELETE_LOCAL_REF (env, thread1_obj); - DELETE_LOCAL_REF (env, thread2_obj); - - if (TRACE_API_CALLS) - tracing (" ==> %s\n", ret ? "TRUE" : "FALSE"); - - return ret; -} - - - - -/************************************************************************/ -/* GLIB interface */ -/************************************************************************/ - -/* set of function pointers to give to glib. */ -GThreadFunctions cp_gtk_portable_native_sync_jni_functions = { - mutex_new_jni_impl, /* mutex_new */ - mutex_lock_jni_impl, /* mutex_lock */ - mutex_trylock_jni_impl, /* mutex_trylock */ - mutex_unlock_jni_impl, /* mutex_unlock */ - mutex_free_jni_impl, /* mutex_free */ - cond_new_jni_impl, /* cond_new */ - cond_signal_jni_impl, /* cond_signal */ - cond_broadcast_jni_impl, /* cond_broadcast */ - cond_wait_jni_impl, /* cond_wait */ - cond_timed_wait_jni_impl, /* cond_timed_wait */ - cond_free_jni_impl, /* cond_free */ - private_new_jni_impl, /* private_new */ - private_get_jni_impl, /* private_get */ - private_set_jni_impl, /* private_set */ - thread_create_jni_impl, /* thread_create */ - thread_yield_jni_impl, /* thread_yield */ - thread_join_jni_impl, /* thread_join */ - thread_exit_jni_impl, /* thread_exit */ - thread_set_priority_jni_impl, /* thread_set_priority */ - thread_self_jni_impl, /* thread_self */ - thread_equal_jni_impl, /* thread_equal */ -}; - - -/* Keep c-font-lock-extra-types in alphabetical order. */ -/* Local Variables: */ -/* c-file-style: "gnu" */ -/* c-font-lock-extra-types: ("\\sw+_t" "gboolean" "GError" "gpointer" - "GPrivate" "GThreadFunc" "GThreadFunctions" "GThreadPriority" - "gulong" - "JNIEnv" - "jboolean" "jclass" "jfieldID" "jint" "jlong" "jmethodID" "jobject" "jstring" "jthrowable" ) */ -/* End: */ diff --git a/native/jni/gtk-peer/gthread-jni.h b/native/jni/gtk-peer/gthread-jni.h deleted file mode 100644 index 3d052dc10..000000000 --- a/native/jni/gtk-peer/gthread-jni.h +++ /dev/null @@ -1,48 +0,0 @@ -/* gthread-jni.h - Copyright (C) 1998, 2002 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -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. */ - -#ifndef __GTHREADJNI_H__ -#define __GTHREADJNI_H__ - -#include -#include -#include "gtkpeer.h" - -extern GThreadFunctions cp_gtk_portable_native_sync_jni_functions; -extern JavaVM *cp_gtk_the_vm; - -#endif /* __GTHREADJNI_H__ */ -- cgit v1.2.1