/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This source file is part of SableVM. * * * * See the file "LICENSE" for the copyright information and for * * the terms and conditions for copying, distribution and * * modification of this source file. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* ---------------------------------------------------------------------- Java_java_lang_VMThread_yield ---------------------------------------------------------------------- */ /* * Class: java_lang_VMThread * Method: yield * Signature: ()V */ JNIEXPORT void JNICALL Java_java_lang_VMThread_yield (JNIEnv *_env, jclass _class) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); _svmf_resuming_java (env); if (sched_yield () != 0) { /* Should we really really throw an error on failure? Maybe we could simply ignore the return value, if no harm is implied. Suggestions are welcome. Etienne */ _svmf_error_InternalError (env); goto end; } end: _svmf_stopping_java (env); return; } /* ---------------------------------------------------------------------- Java_java_lang_VMThread_nativeIsAlive ---------------------------------------------------------------------- */ /* * Class: java_lang_VMThread * Method: nativeIsAlive * Signature: ([B)Z */ JNIEXPORT jboolean JNICALL Java_java_lang_VMThread_nativeIsAlive (JNIEnv *_env, jobject this, jbyteArray vmData) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); jboolean result; _svmf_resuming_java (env); result = ((_svmt_JNIEnv *) _svmf_unwrap_pointer (*vmData))->is_alive; _svmf_stopping_java (env); return result; } /* ---------------------------------------------------------------------- Java_java_lang_VMThread_nativeStart ---------------------------------------------------------------------- */ /* * Class: java_lang_VMThread * Method: nativeStart * Signature: ()[B */ JNIEXPORT jbyteArray JNICALL Java_java_lang_VMThread_nativeStart (JNIEnv *_env, jobject this, jobject threadInstance) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); jbyteArray result = NULL; _svmf_resuming_java (env); { _svmt_JavaVM *vm = env->vm; _svmt_JNIEnv *new_env = NULL;; { jint status = JNI_OK; _svmm_mutex_lock (vm->global_mutex); if (vm->threads.free_list != NULL) { new_env = vm->threads.free_list; assert (new_env->previous == NULL); vm->threads.free_list = new_env->next; if (vm->threads.free_list != NULL) { vm->threads.free_list->previous = NULL; } new_env->next = vm->threads.user; if (new_env->next != NULL) { assert (new_env->next->previous == NULL); new_env->next->previous = new_env; } new_env->thread_status = SVM_THREAD_STATUS_RUNNING_JAVA; } else if (vm->threads.next_thread_id <= SVM_MAX_THREAD_ID) { if (_svmm_gzalloc_env_no_exception (new_env) != JNI_OK) { goto unlock; } new_env->interface = &_svmv_native_interface; new_env->vm = vm; new_env->next = vm->threads.user; vm->threads.user = new_env; if (new_env->next != NULL) { assert (new_env->next->previous == NULL); new_env->next->previous = new_env; } new_env->thread.interrupted_status = 0; new_env->thread.sleeping_on_fat_lock = NULL; new_env->thread.id = vm->threads.next_thread_id++; _svmf_initialize_thinlock_id (new_env); vm->threads.array[new_env->thread.id] = new_env; _svmm_mutex_init (new_env->contention.owner.mutex); _svmm_cond_init (new_env->contention.requester.cond); new_env->thread_status = SVM_THREAD_STATUS_RUNNING_JAVA; } else { status = JNI_ERR; } unlock: _svmm_mutex_unlock (); if (status != JNI_OK) { _svmf_error_OutOfMemoryError (env); goto end; } } if (_svmm_gzalloc_native_ref_no_exception (new_env->native_locals.list) != JNI_OK) { /* we should be cleaning up! todo ... */ _svmf_error_OutOfMemoryError (env); goto end; } new_env->throwable = _svmf_cast_jobject_nref (new_env->native_locals.list); if (_svmm_gzalloc_native_ref_no_exception (new_env->native_locals.list->next) != JNI_OK) { /* we should be cleaning up! todo ... */ _svmf_error_OutOfMemoryError (env); goto end; } new_env->thread.thread_instance = _svmf_cast_jobject_nref (new_env->native_locals.list->next); *(new_env->thread.thread_instance) = *(threadInstance); if (_svmm_gzalloc_native_ref_no_exception (new_env->native_locals.list->next->next) != JNI_OK) { /* we should be cleaning up! todo ... */ _svmf_error_OutOfMemoryError (env); goto end; } new_env->contention.requester.jobject = _svmf_cast_jobject_nref (new_env->native_locals.list->next->next); if (_svmf_stack_init (new_env) != JNI_OK) { /* we should be cleaning up! todo ... */ *(env->throwable) = *(new_env->throwable); goto end; } /* start it! */ new_env->is_alive = JNI_TRUE; if (pthread_create (&new_env->thread.pthread, NULL, &_svmf_thread_start, new_env) != 0) { /* something went wrong */ /* we should be cleaning up! todo ... */ new_env->is_alive = JNI_FALSE; _svmf_error_InternalError (env); goto end; } /* it's started! */ result = _svmf_get_jni_frame_native_local_array (env); if (_svmf_wrap_pointer (env, new_env, result) != JNI_OK) { result = NULL; goto end; } } end: _svmf_stopping_java (env); return result; } /* ---------------------------------------------------------------------- Java_java_lang_VMThread_currentThread ---------------------------------------------------------------------- */ /* * Class: java_lang_VMThread * Method: currentThread * Signature: ()Ljava/lang/Thread; */ JNIEXPORT jobject JNICALL Java_java_lang_VMThread_currentThread (JNIEnv *_env, jclass _class) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); jobject result = NULL; _svmf_resuming_java (env); { if (env->thread.thread_instance == NULL) { jobject thread; jbyteArray wrapper; if (_svmm_new_native_local (env, thread) != JNI_OK) { goto end; } if (_svmm_local_wrap_pointer (env, env, wrapper) != JNI_OK) { _svmm_free_native_local (env, thread); goto end; } if (_svmm_invoke_static_virtualmachine_createrootthread (env, _svmf_cast_jobject (wrapper), thread) != JNI_OK) { _svmm_free_native_local_array (env, wrapper); _svmm_free_native_local (env, thread); goto end; } _svmm_free_native_local_array (env, wrapper); env->thread.thread_instance = thread; } result = _svmf_get_jni_frame_native_local (env); *result = *(env->thread.thread_instance); } end: _svmf_stopping_java (env); return result; } /* ---------------------------------------------------------------------- Java_java_lang_VMThread_nativeInterrupt ---------------------------------------------------------------------- */ /* * Class: java_lang_VMThread * Method: interrupt * Signature: ()V */ JNIEXPORT void JNICALL Java_java_lang_VMThread_nativeInterrupt (JNIEnv *_env, jobject this, jbyteArray vmData) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); _svmt_JNIEnv *target_env = (_svmt_JNIEnv *) _svmf_unwrap_pointer (*vmData); _svmt_fat_lock *sleeping_on_fat_lock; _svmt_word old_interrupted_status, new_interrupted_status; _svmf_resuming_java (env); again: /* where is the target thread possibly sleeping? */ do { old_interrupted_status = target_env->thread.interrupted_status; new_interrupted_status = old_interrupted_status; if (old_interrupted_status & SVM_THREAD_INTERRUPTIBLE_BY_SIGNAL) { new_interrupted_status |= SVM_THREAD_THROW_INTERRUPTED; new_interrupted_status &= ~SVM_THREAD_INTERRUPTED; } else if (old_interrupted_status & SVM_THREAD_INTERRUPTIBLE_ON_FAT_LOCK) { /* do nothing, we're not sure yet what the target thread is doing */ } else { new_interrupted_status |= SVM_THREAD_INTERRUPTED; } } while (!_svmm_compare_and_swap (target_env->thread.interrupted_status, old_interrupted_status, new_interrupted_status)); if (old_interrupted_status & SVM_THREAD_INTERRUPTIBLE_ON_FAT_LOCK) { /* the target thread is probably sleeping on a fat lock */ sleeping_on_fat_lock = target_env->thread.sleeping_on_fat_lock; if (sleeping_on_fat_lock != NULL) { if (_svmm_mutex_trylock (sleeping_on_fat_lock->mutex) == 0) { /* make sure the thread is _still_ sleeping on this lock! */ if (sleeping_on_fat_lock == target_env->thread.sleeping_on_fat_lock) { /* Only now we can be sure that the target thread is sleeping and we can * effectively interrupt him and tell him to throw InterruptedException */ do { old_interrupted_status = target_env->thread.interrupted_status; new_interrupted_status = old_interrupted_status; new_interrupted_status |= SVM_THREAD_THROW_INTERRUPTED; new_interrupted_status &= ~SVM_THREAD_INTERRUPTED; } while (!_svmm_compare_and_swap (target_env->thread.interrupted_status, old_interrupted_status, new_interrupted_status)); /* free the sleeping/target thread */ _svmm_cond_broadcast (sleeping_on_fat_lock-> notification_cond); _svmm_mutex_unlock_after_try (sleeping_on_fat_lock->mutex); } else { _svmm_mutex_unlock_after_try (sleeping_on_fat_lock->mutex); /* We haven't managed to block&interrupt the target thread - trying again. */ goto again; } } else goto again; } else goto again; } else if (old_interrupted_status & SVM_THREAD_INTERRUPTIBLE_BY_SIGNAL) { _svmm_kill (target_env->thread.pthread, SVM_INTERRUPT_SIGNAL); } _svmf_stopping_java (env); return; } /* ---------------------------------------------------------------------- Java_java_lang_VMThread_nativeIsInterrupted ---------------------------------------------------------------------- */ /* * Class: java_lang_VMThread * Method: isInterrupted * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_java_lang_VMThread_nativeIsInterrupted (JNIEnv *_env, jobject this, jbyteArray vmData) { jboolean result; _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); _svmf_resuming_java (env); result = (((_svmt_JNIEnv *) _svmf_unwrap_pointer (*vmData))->thread. interrupted_status) & SVM_THREAD_INTERRUPTED; _svmf_stopping_java (env); return result; } /* ---------------------------------------------------------------------- Java_java_lang_VMThread_interrupted ---------------------------------------------------------------------- */ /* * Class: java_lang_VMThread * Method: interrupted * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_java_lang_VMThread_interrupted (JNIEnv *_env, jclass this) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); _svmt_word old_interrupted_status, new_interrupted_status; jboolean result; _svmf_resuming_java (env); /* this is static method that refers to the _current_ thread only, so no need to search which thread is referred to by "this" */ do { old_interrupted_status = env->thread.interrupted_status; new_interrupted_status = old_interrupted_status; new_interrupted_status &= ~SVM_THREAD_INTERRUPTED; } while (!_svmm_compare_and_swap (env->thread.interrupted_status, old_interrupted_status, new_interrupted_status)); result = old_interrupted_status & SVM_THREAD_INTERRUPTED; _svmf_stopping_java (env); return result; }