#include "gthread-jni.h"
JavaVM *gdk_vm;
static void maybe_rethrow(JNIEnv *gdk_env, char *message, char *file, int line) {
jthrowable cause;
jstring jmessage;
jclass obj_class;
jobject obj;
jmethodID ctor;
int len;
char *buf;
if ((cause = (*gdk_env)->ExceptionOccurred(gdk_env)) != NULL)
{
len = strlen(message) + strlen(file) + 25;
buf = (char *) malloc(len);
if (buf != NULL)
{
bzero(buf, len);
sprintf(buf, "%s (at %s:%d)", message, file, line);
jmessage = (*gdk_env)->NewStringUTF(gdk_env, buf);
free(buf);
}
else
jmessage = NULL;
obj_class = (*gdk_env)->FindClass (gdk_env,
"java/lang/RuntimeException");
ctor = (*gdk_env)->GetMethodID(gdk_env, obj_class, "<init>",
"(Ljava/langString;Ljava/lang/Throwable)V");
obj = (*gdk_env)->NewObject (gdk_env, obj_class, ctor, jmessage, cause);
(*gdk_env)->Throw(gdk_env, (jthrowable)obj);
}
}
#define MAYBE_RETHROW(_class, _message) \
maybe_rethrow(_class, _message, __FILE__, __LINE__)
static jobject *allocatePlainObject() {
jclass obj_class;
jobject *obj;
JNIEnv *gdk_env;
jmethodID ctor;
(*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
obj_class = (*gdk_env)->FindClass (gdk_env, "java/lang/Object");
MAYBE_RETHROW(gdk_env, "cannot find Object");
ctor = (*gdk_env)->GetMethodID(gdk_env, obj_class, "<init>", "()V");
MAYBE_RETHROW(gdk_env, "cannot find constructor");
obj = (jobject *) g_malloc (sizeof (jobject));
*obj = (*gdk_env)->NewObject (gdk_env, obj_class, ctor);
MAYBE_RETHROW(gdk_env, "cannot allocate object");
*obj = (*gdk_env)->NewGlobalRef (gdk_env, *obj);
MAYBE_RETHROW(gdk_env, "cannot make global ref");
return obj;
}
static void freePlainObject(jobject *obj) {
JNIEnv *gdk_env;
if (obj) {
(*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
(*gdk_env)->DeleteGlobalRef (gdk_env, *obj);
MAYBE_RETHROW(gdk_env, "cannot delete global ref");
g_free (obj);
}
}
static void takeLock(JNIEnv *gdk_env, void *mutex) {
(*gdk_env)->MonitorEnter (gdk_env, *((jobject *)mutex));
MAYBE_RETHROW(gdk_env, "cannot get lock");
}
static void releaseLock(JNIEnv *gdk_env, void *mutex) {
(*gdk_env)->MonitorExit (gdk_env, *((jobject *)mutex));
MAYBE_RETHROW(gdk_env, "cannot release lock");
}
static GMutex *g_mutex_new_jni_impl (void) {
return (GMutex*) allocatePlainObject();
}
static void g_mutex_lock_jni_impl (GMutex *mutex __attribute__((unused))) {
JNIEnv *gdk_env;
(*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
takeLock(gdk_env, mutex);
}
static gboolean g_mutex_trylock_jni_impl
(GMutex *mutex __attribute__((unused)))
{
return FALSE;
}
static void g_mutex_unlock_jni_impl (GMutex *mutex) {
JNIEnv *gdk_env;
(*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
releaseLock(gdk_env, mutex);
}
static void g_mutex_free_jni_impl (GMutex *mutex)
{
freePlainObject( (jobject*)mutex );
}
static GCond *g_cond_new_jni_impl () {
return (GCond*)allocatePlainObject();
}
static void g_cond_signal_jni_impl (GCond *cond) {
jclass lcl_class;
jmethodID signal_mth;
JNIEnv *gdk_env;
(*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Object");
MAYBE_RETHROW(gdk_env, "cannot find Object");
signal_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "notify", "()V");
MAYBE_RETHROW(gdk_env, "cannot find Object.<notify>");
takeLock(gdk_env, cond);
(*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)cond, signal_mth);
MAYBE_RETHROW(gdk_env, "cannot signal mutex");
releaseLock(gdk_env, cond);
}
static void g_cond_broadcast_jni_impl (GCond *cond) {
jclass lcl_class;
jmethodID bcast_mth;
JNIEnv *gdk_env;
(*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Object");
MAYBE_RETHROW(gdk_env, "cannot find Object");
bcast_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "notifyAll", "()V");
MAYBE_RETHROW(gdk_env, "cannot find Object.<notifyAll>");
takeLock(gdk_env, cond);
(*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)cond, bcast_mth);
MAYBE_RETHROW(gdk_env, "cannot broadcast to mutex");
releaseLock(gdk_env, cond);
}
static void g_cond_wait_jni_impl
(GCond *cond, GMutex *mutex __attribute__((unused)))
{
jclass lcl_class;
jmethodID wait_mth;
JNIEnv *gdk_env;
(*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Object");
MAYBE_RETHROW(gdk_env, "cannot find Object");
wait_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "wait", "()V");
MAYBE_RETHROW(gdk_env, "cannot find Object.<wait>");
takeLock(gdk_env, cond);
(*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)cond, wait_mth);
MAYBE_RETHROW(gdk_env, "cannot wait on mutex");
releaseLock(gdk_env, cond);
}
static gboolean
g_cond_timed_wait_jni_impl
(GCond *cond, GMutex *mutex __attribute__((unused)),
GTimeVal *end_time)
{
jclass lcl_class;
jmethodID wait_mth;
JNIEnv *gdk_env;
jlong time;
jthrowable cause;
(*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Object");
MAYBE_RETHROW(gdk_env, "cannot find Object");
wait_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "wait", "(J)V");
MAYBE_RETHROW(gdk_env, "cannot find Object.<wait(J)>");
time = end_time->tv_sec*1000;
time += end_time->tv_usec/1000;
takeLock(gdk_env, cond);
(*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)cond, wait_mth, time);
if ((cause = (*gdk_env)->ExceptionOccurred(gdk_env)) != NULL) {
jclass intr = (*gdk_env)->FindClass (gdk_env, "java.lang.InterruptedException");
if ( (*gdk_env)->IsInstanceOf(gdk_env, cause, intr) ) {
releaseLock(gdk_env, cond);
return FALSE;
} else {
MAYBE_RETHROW(gdk_env, "error in timed wait");
}
}
releaseLock(gdk_env, cond);
return TRUE;
}
static void g_cond_free_jni_impl (GCond *cond) {
freePlainObject( (jobject*)cond );
}
static GPrivate *g_private_new_jni_impl
(GDestroyNotify notify __attribute__((unused)))
{
jclass lcl_class;
jobject *local;
JNIEnv *gdk_env;
jmethodID ctor;
(*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.ThreadLocal");
MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal");
ctor = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "<init>", "()V");
MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal.<init>");
local = (jobject *) g_malloc (sizeof (jobject));
*local = (*gdk_env)->NewObject(gdk_env, lcl_class, ctor);
MAYBE_RETHROW(gdk_env, "cannot allocate a ThreadLocal");
*local = ((*gdk_env)->NewGlobalRef (gdk_env, *local));
MAYBE_RETHROW(gdk_env, "cannot create a GlobalRef");
return (GPrivate*) local;
}
static gpointer g_private_get_jni_impl (GPrivate *private) {
jclass lcl_class;
jobject lcl_obj;
JNIEnv *gdk_env;
jmethodID get_mth;
jclass int_class;
jmethodID val_mth;
jint int_val;
(*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.ThreadLocal");
MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal");
get_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "get", "()Ljava/lang/Object;");
MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal.<get>");
lcl_obj = (*gdk_env)->CallObjectMethod(gdk_env, *(jobject*)private, get_mth);
MAYBE_RETHROW(gdk_env, "cannot find thread-local object");
int_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Integer");
MAYBE_RETHROW(gdk_env, "cannot find Integer");
val_mth = (*gdk_env)->GetMethodID(gdk_env, int_class, "intValue", "()I");
MAYBE_RETHROW(gdk_env, "cannot find Integer.<intValue>");
int_val = (*gdk_env)->CallIntMethod(gdk_env, lcl_obj, val_mth);
MAYBE_RETHROW(gdk_env, "cannot get thread local value");
return (gpointer) int_val;
}
static void g_private_set_jni_impl (GPrivate *private, gpointer data) {
jclass lcl_class, int_class;
jobject lcl_obj;
JNIEnv *gdk_env;
jmethodID new_int, set_mth;
(*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1);
int_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Integer");
MAYBE_RETHROW(gdk_env, "cannot find Integer");
new_int = (*gdk_env)->GetMethodID(gdk_env, int_class, "<init>", "(I)V");
MAYBE_RETHROW(gdk_env, "cannot find Integer.<init>");
lcl_obj = (*gdk_env)->NewObject(gdk_env, int_class, new_int, (jint)data);
MAYBE_RETHROW(gdk_env, "cannot create an Integer");
lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.ThreadLocal");
MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal");
set_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "set", "(Ljava/lang/Object;)V");
MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal.<set>");
(*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)private, set_mth, lcl_obj);
MAYBE_RETHROW(gdk_env, "cannot set thread local value");
}
GThreadFunctions g_thread_jni_functions =
{
g_mutex_new_jni_impl,
g_mutex_lock_jni_impl,
g_mutex_trylock_jni_impl,
g_mutex_unlock_jni_impl,
g_mutex_free_jni_impl,
g_cond_new_jni_impl,
g_cond_signal_jni_impl,
g_cond_broadcast_jni_impl,
g_cond_wait_jni_impl,
g_cond_timed_wait_jni_impl,
g_cond_free_jni_impl,
g_private_new_jni_impl,
g_private_get_jni_impl,
g_private_set_jni_impl,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};