#include <config.h>
#define TRACE_API_CALLS 0
#define TRACE_MONITORS 0
#define EXPLAIN_TROUBLE 1
#define EXPLAIN_BROKEN 1
#define DIE_IF_BROKEN 1
#if DIE_IF_BROKEN
#define DIE_IF_BADLY_BROKEN 1
#else
#define DIE_IF_BADLY_BROKEN 1
#endif
#define ENABLE_EXPENSIVE_ASSERTIONS 0
#define DELETE_LOCAL_REFS 1
#define HAVE_JNI_VERSION_1_2 0
#if defined HAVE_STDINT_H
#include <stdint.h>
#elif defined HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include <stdarg.h>
#include <glib.h>
#include "gthread-jni.h"
#include <assert.h>
#include <gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h>
#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
JavaVM *the_vm;
union env_union
{
void **void_env;
JNIEnv **jni_env;
};
union func_union
{
void *void_func;
GThreadFunc g_func;
};
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));
#define WHERE __FILE__ ":" G_STRINGIFY(__LINE__) ": "
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);
}
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
#endif
#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)
jclass runtimeException_class;
jmethodID runtimeException_ctor;
static int
throw (JNIEnv * env, jthrowable cause, const char *message,
gboolean isBroken, const char *file, int line)
{
jstring jmessage;
gboolean describedException = FALSE;
jthrowable wrapper;
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);
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 (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;
}
wrapper = (jthrowable) (*env)->NewObject
(env, runtimeException_class, runtimeException_ctor, jmessage, cause);
DELETE_LOCAL_REF (env, jmessage);
if (!wrapper)
{
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;
}
if ((*env)->Throw (env, wrapper))
{
BADLY_BROKEN1
("GNU Classpath: Failure of JNI Throw to report an Exception");
return -1;
}
DELETE_LOCAL_REF (env, wrapper);
return 1;
}
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);
}
static int
maybe_rethrow (JNIEnv * env, const char *message, gboolean isBroken,
const char *file, int line)
{
jthrowable cause = (*env)->ExceptionOccurred (env);
int ret = 0;
if (cause)
{
ret = rethrow (env, cause, message, isBroken, file, line);
DELETE_LOCAL_REF (env, cause);
}
return 0;
}
#define MAYBE_TROUBLE(_env, _message) \
maybe_rethrow(_env, _message, FALSE, __FILE__, __LINE__)
#define MAYBE_BROKEN(_env, _message) \
maybe_rethrow(_env, _message, TRUE, __FILE__, __LINE__)
#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__)
#define NEW_TROUBLE(_env, _message) \
throw (_env, NULL, _message, FALSE, __FILE__, __LINE__)
#define NEW_BROKEN(_env, _message) \
throw (_env, NULL, _message, TRUE, __FILE__, __LINE__)
#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__)
#if 1
#define HIDE_OLD_TROUBLE(env) \
assert ( NULL == (*env)->ExceptionOccurred (env) )
#define SHOW_OLD_TROUBLE() \
assert ( NULL == (*env)->ExceptionOccurred (env) )
#else
#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
static int
setup_exception_cache (JNIEnv * env)
{
static int exception_cache_initialized = 0;
jclass lcl_class;
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;
}
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, "<init>",
"(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;
}
static jclass obj_class;
static jmethodID obj_ctor;
static jmethodID obj_notify_mth;
static jmethodID obj_notifyall_mth;
static jmethodID obj_wait_mth;
static jmethodID obj_wait_nanotime_mth;
static jclass mutex_class;
static jmethodID mutex_ctor;
static jfieldID mutex_lockForPotentialLockers_fld;
static jfieldID mutex_potentialLockers_fld;
static jclass thread_class;
static jmethodID thread_current_mth;
static jmethodID thread_equals_mth;
static jmethodID thread_join_mth;
static jmethodID thread_setPriority_mth;
static jmethodID thread_stop_mth;
static jmethodID thread_yield_mth;
static jclass threadlocal_class;
static jmethodID threadlocal_ctor;
static jmethodID threadlocal_set_mth;
static jmethodID threadlocal_get_mth;
static jclass long_class;
static jmethodID long_ctor;
static jmethodID long_longValue_mth;
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;
static jclass interrupted_exception_class;
static int
setup_cache (JNIEnv * env)
{
jclass lcl_class;
static int initialized = 0;
if (initialized)
return initialized;
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));
lcl_class = (*env)->FindClass (env, "java/lang/Object");
if (!lcl_class)
{
BROKEN (env, "cannot find java.lang.Object");
return initialized = -1;
}
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, "<init>", "()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.<wait()V>");
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.<wait(JI)V>");
return initialized = -1;
}
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;
}
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, "<init>", "()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;
}
if (! (lcl_class = (*env)->FindClass (env, "java/lang/Thread")))
{
BROKEN (env, "cannot find java.lang.Thread");
return initialized = -1;
}
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;
}
lcl_class = (*env)->FindClass (env, "java/lang/ThreadLocal");
if ( ! lcl_class )
{
BROKEN (env, "cannot find class java.lang.ThreadLocal");
return initialized = -1;
}
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,
"<init>", "()V");
if ( ! threadlocal_ctor )
{
BROKEN (env, "cannot find ThreadLocal.<init>()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;
}
lcl_class = (*env)->FindClass (env, "java/lang/Long");
if ( ! lcl_class )
{
BROKEN (env, "cannot find class java.lang.Long");
return initialized = -1;
}
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, "<init>", "(J)V");
if (!long_ctor)
{
BROKEN (env, "cannot find method java.lang.Long.<init>(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;
}
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;
}
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, "<init>", "(JJZ)V");
if ( ! runner_ctor )
{
BROKEN (env,
"cannot find method GThreadNativeMethodRunner.<init>(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;
}
lcl_class = (*env)->FindClass (env, "java/lang/InterruptedException");
if ( ! lcl_class )
{
BROKEN (env, "cannot find class java.lang.InterruptedException");
return initialized = -1;
}
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;
}
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");
}
return global_obj;
}
static void
freeObject (JNIEnv * env, jobject obj)
{
if (obj)
{
(*env)->DeleteGlobalRef (env, obj);
}
}
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");
}
return global_obj;
}
#define ENTER_MONITOR(env, m) \
enterMonitor(env, m, G_STRINGIFY(m))
static int
enterMonitor (JNIEnv * env, jobject monitorObj, const char monName[])
{
if (TRACE_MONITORS)
tracing (" <MonitorEnter(%s)>", monName);
assert (monitorObj);
if ((*env)->MonitorEnter (env, monitorObj) < 0)
{
BROKEN (env, "cannot enter monitor");
return -1;
}
return 0;
}
#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 (" <MonitorExit(%s)>", monName);
assert (mutexObj);
if ((*env)->MonitorExit (env, mutexObj) < 0)
{
BROKEN (env, "cannot exit monitor ");
return -1;
}
return 0;
}
static jobject
getThreadFromThreadID (JNIEnv * env, gpointer gThreadID)
{
jint threadNum = (jint) 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;
}
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 (gpointer) threadNum;
}
struct mutexObj_cache
{
jobject lockForPotentialLockersObj;
jobject lockObj;
};
static int
populate_mutexObj_cache (JNIEnv * env, jobject mutexObj,
struct mutexObj_cache *mcache)
{
mcache->lockObj = mutexObj;
assert (mcache->lockObj);
mcache->lockForPotentialLockersObj = (*env)->GetObjectField
(env, mutexObj, mutex_lockForPotentialLockers_fld);
assert (mcache->lockForPotentialLockersObj);
return 0;
}
static void
clean_mutexObj_cache (JNIEnv * env, struct mutexObj_cache *mcache)
{
DELETE_LOCAL_REF (env, mcache->lockForPotentialLockersObj);
mcache->lockObj = NULL;
}
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);
++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;
}
static int
mutexObj_unlock (JNIEnv * env, jobject mutexObj,
struct mutexObj_cache *mcache)
{
jint potentialLockers;
int ret = -1;
if (EXIT_MONITOR (env, mcache->lockObj) < 0)
goto done;
if (ENTER_MONITOR (env, mcache->lockForPotentialLockersObj) < 0)
goto done;
potentialLockers = (*env)->GetIntField
(env, mutexObj, mutex_potentialLockers_fld);
assert (potentialLockers >= 1);
--potentialLockers;
(*env)->SetIntField
(env, mutexObj, mutex_potentialLockers_fld, potentialLockers);
if (EXIT_MONITOR (env, mcache->lockForPotentialLockersObj) < 0)
goto done;
ret = 0;
done:
return ret;
}
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;
(*the_vm)->GetEnv (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;
}
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;
(*the_vm)->GetEnv (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);
done:
clean_mutexObj_cache (env, &mcache);
if (TRACE_API_CALLS)
tracing (" ==> VOID \n");
}
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;
(*the_vm)->GetEnv (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)
{
EXIT_MONITOR (env, mcache.lockForPotentialLockersObj);
goto done;
}
if (ENTER_MONITOR (env, mcache.lockObj))
{
EXIT_MONITOR (env, mcache.lockForPotentialLockersObj);
goto done;
}
potentialLockers = 1;
(*env)->SetIntField
(env, mutexObj, mutex_potentialLockers_fld, potentialLockers);
ret = TRUE;
if (EXIT_MONITOR (env, mcache.lockForPotentialLockersObj))
goto done;
SHOW_OLD_TROUBLE ();
done:
clean_mutexObj_cache (env, &mcache);
if (TRACE_API_CALLS)
tracing (" ==> %s\n", ret ? "TRUE" : "FALSE");
return ret;
}
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;
(*the_vm)->GetEnv (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");
}
static void
mutex_free_jni_impl (GMutex * mutex)
{
jobject mutexObj = (jobject) mutex;
JNIEnv *env;
union env_union e;
e.jni_env = &env;
(*the_vm)->GetEnv (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");
}
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;
(*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
condObj = allocatePlainObject (env);
if (TRACE_API_CALLS)
tracing (" ==> %p\n", condObj);
return (GCond *) condObj;
}
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;
(*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
if (setup_cache (env) < 0)
goto done;
HIDE_OLD_TROUBLE (env);
assert (condObj);
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");
}
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;
(*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
if (setup_cache (env) < 0)
goto done;
HIDE_OLD_TROUBLE (env);
assert (condObj);
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");
}
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;
(*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
if (setup_cache (env) < 0)
goto done;
HIDE_OLD_TROUBLE (env);
assert (condObj);
assert (mutexObj);
if (ENTER_MONITOR (env, condObj) < 0)
goto done;
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);
goto done;
}
if (mutexObj_lock (env, mutexObj, &cache))
goto done;
EXIT_MONITOR (env, condObj);
SHOW_OLD_TROUBLE ();
done:
if (TRACE_API_CALLS)
tracing (" ==> VOID\n");
}
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;
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;
(*the_vm)->GetEnv (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);
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);
cause = (*env)->ExceptionOccurred (env);
if ( ! cause )
{
condRaised = TRUE;
}
else if ((*env)->IsInstanceOf (env, cause, interrupted_exception_class))
{
condRaised = FALSE;
(*env)->ExceptionClear (env);
cause = NULL;
}
else
{
interrupted = FALSE;
}
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)
{
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;
}
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;
(*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
freeObject (env, condObj);
if (TRACE_API_CALLS)
tracing (" ==> VOID\n");
}
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;
if (TRACE_API_CALLS)
tracing ("private_new_jni_impl()");
e.jni_env = &env;
(*the_vm)->GetEnv (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;
}
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;
jlong val;
if (TRACE_API_CALLS)
tracing ("private_get_jni_impl(keyObj=%p)", keyObj);
e.jni_env = &env;
(*the_vm)->GetEnv (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 )
{
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;
SHOW_OLD_TROUBLE ();
done:
if (TRACE_API_CALLS)
tracing (" ==> %p\n", thread_specific_data);
return thread_specific_data;
}
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;
(*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
if (setup_cache (env) < 0)
goto done;
HIDE_OLD_TROUBLE (env);
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;
}
(*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");
}
static void
thread_create_jni_impl (GThreadFunc func,
gpointer data,
gulong stack_size __attribute__((unused)),
gboolean joinable,
gboolean bound __attribute__((unused)),
GThreadPriority gpriority,
gpointer threadIDp,
GError **errorp __attribute__((unused)))
{
JNIEnv *env;
union env_union e;
union func_union f;
jboolean jjoinable = joinable;
jobject newThreadObj;
gpointer threadID;
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;
(*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
if (setup_cache (env) < 0)
{
*(gpointer *) threadIDp = NULL;
goto done;
}
HIDE_OLD_TROUBLE (env);
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;
goto done;
}
if (threadObj_set_priority (env, newThreadObj, gpriority) < 0)
{
*(gpointer *) threadIDp = NULL;
goto done;
}
(*env)->CallVoidMethod (env, runner_class, runner_start_mth);
if (MAYBE_BROKEN (env, "starting a new thread failed"))
{
*(gpointer *) threadIDp = NULL;
goto done;
}
threadID = getThreadIDFromThread (env, newThreadObj);
*(gpointer *) threadIDp = threadID;
SHOW_OLD_TROUBLE ();
done:
if (TRACE_API_CALLS)
tracing (" ==> (threadID = %p) \n", threadID);
}
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;
(*the_vm)->GetEnv (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;
(*the_vm)->GetEnv (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 )
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");
}
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;
(*the_vm)->GetEnv (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");
}
static jint
javaPriorityLevel (GThreadPriority priority)
{
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 ();
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;
}
}
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;
(*the_vm)->GetEnv (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)
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");
}
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");
}
static void
thread_self_jni_impl (
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;
(*the_vm)->GetEnv (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;
(*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1);
if (setup_cache (env) < 0)
{
ret = FALSE;
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;
}
GThreadFunctions portable_native_sync_jni_functions = {
mutex_new_jni_impl,
mutex_lock_jni_impl,
mutex_trylock_jni_impl,
mutex_unlock_jni_impl,
mutex_free_jni_impl,
cond_new_jni_impl,
cond_signal_jni_impl,
cond_broadcast_jni_impl,
cond_wait_jni_impl,
cond_timed_wait_jni_impl,
cond_free_jni_impl,
private_new_jni_impl,
private_get_jni_impl,
private_set_jni_impl,
thread_create_jni_impl,
thread_yield_jni_impl,
thread_join_jni_impl,
thread_exit_jni_impl,
thread_set_priority_jni_impl,
thread_self_jni_impl,
thread_equal_jni_impl,
};