📄 gthread-jni.c
字号:
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;}/************************************************************************//* 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 intpopulate_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 voidclean_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 intmutexObj_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 intmutexObj_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; (*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;}/* Lock a mutex. */static voidmutex_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); /* 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 gbooleanmutex_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) { /* 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 voidmutex_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");}/* Free a mutex (isn't C fun?). OK this time for it to be NULL. No failure conditions, for a change. */static voidmutex_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");}/************************************************************************//* 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; (*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;}/* Signal on a condition variable. This is simply calling Object.notify * for us. */static voidcond_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); /* 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 voidcond_broadcast_jni_impl (GCond * gcond){ jobject condObj = (jobject) gcond; JNIEnv *env; union env_union e; if (TRACE_API_CALLS)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -