📄 gthread-jni.c
字号:
/* 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 modifyit under the terms of the GNU General Public License as published bythe 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, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUGeneral Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Classpath; see the file COPYING. If not, write to theFree Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA02110-1301 USA.Linking this library statically or dynamically with other modules ismaking a combined work based on this library. Thus, the terms andconditions of the GNU General Public License cover the wholecombination.As a special exception, the copyright holders of this library give youpermission to link this library with independent modules to produce anexecutable, regardless of the license terms of these independentmodules, and to copy and distribute the resulting executable underterms of your choice, provided that you also meet, for each linkedindependent module, the terms and conditions of the license of thatmodule. An independent module is a module which is not derived fromor based on this library. If you modify this library, you may extendthis exception to your version of the library, but you are notobligated to do so. If you do not wish to do so, delete thisexception statement from your version. *//************************************************************************//* Header *//************************************************************************//* * @author Julian Dolby (dolby@us.ibm.com) * @date February 7, 2003 implemented for GLIB v.1 * * * @author Steven Augart * <steve+classpath at augart dot com>, <augart at watson dot ibm dot com> * @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 <config.h>/************************************************************************//* 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 <stdint.h> /* provides intptr_t */#elif defined HAVE_INTTYPES_H#include <inttypes.h>#endif#include <stdarg.h> /* va_list */#include <glib.h>#include "gthread-jni.h"#include <assert.h> /* assert() *//* For Java thread priority constants. */#include <gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h>/* 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 voidfatalMsg (const char fmt[], ...){ va_list ap; va_start (ap, fmt); vfprintf (stderr, fmt, ap); va_end (ap); fputs ("\nAborting execution\n", stderr); abort ();}static voidcriticalMsg (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 voidtracing (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 intthrow (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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -