/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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_VMObject_notify ---------------------------------------------------------------------- */ /* * Class: java_lang_VMObject * Method: notify * Signature: (Ljava/lang/Object;)V */ JNIEXPORT static void JNICALL Java_java_lang_VMObject_notify (JNIEnv *_env, jclass class, jobject o) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); _svmt_JavaVM *vm = env->vm; _svmf_resuming_java (env); { _svmt_object_instance *instance = *o; _svmt_word lockword = instance->lockword; if (_svmf_lockword_is_thin (lockword)) { if (_svmf_lockword_get_thinlock_id (lockword) != env->thread.thinlock_id) { _svmf_error_IllegalMonitorStateException (env); goto end; } /* It's a thinlock; no other thread is possibly waiting on this object's monitor. No need to notify. */ goto end; } /* It's a fat lock. */ { jint fat_id = _svmf_lockword_get_fatlock_index (lockword); _svmt_JNIEnv *fat_lock = vm->threads.array[fat_id]; if (fat_lock->fatlock.owner != env) { _svmf_error_IllegalMonitorStateException (env); goto end; } _svmm_debug_synchronization (env, "will notify one of %d threads on fatlock (%d) we own", fat_lock->fatlock.threads_waiting_no, fat_id, NULL, NULL); /* Time to notify. */ _svmm_mutex_lock (fat_lock->fatlock.mutex); _svmm_cond_signal (fat_lock->fatlock.notification_cond); _svmm_mutex_unlock (); } } end: _svmf_stopping_java (env); } /* ---------------------------------------------------------------------- Java_java_lang_VMObject_notifyAll ---------------------------------------------------------------------- */ /* * Class: java_lang_VMObject * Method: notifyAll * Signature: (Ljava/lang/Object;)V */ JNIEXPORT static void JNICALL Java_java_lang_VMObject_notifyAll (JNIEnv *_env, jclass class, jobject o) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); _svmt_JavaVM *vm = env->vm; _svmf_resuming_java (env); { _svmt_object_instance *instance = *o; _svmt_word lockword = instance->lockword; if (_svmf_lockword_is_thin (lockword)) { if (_svmf_lockword_get_thinlock_id (lockword) != env->thread.thinlock_id) { _svmf_error_IllegalMonitorStateException (env); goto end; } /* It's a thinlock; no other thread is possibly waiting on this object's monitor. No need to notify. */ goto end; } /* It's a fat lock. */ { jint fat_id = _svmf_lockword_get_fatlock_index (lockword); _svmt_JNIEnv *fat_lock = vm->threads.array[fat_id]; if (fat_lock->fatlock.owner != env) { _svmf_error_IllegalMonitorStateException (env); goto end; } _svmm_debug_synchronization (env, "will notifyAll %d threads on fatlock (%d) we own", fat_lock->fatlock.threads_waiting_no, fat_id, NULL, NULL); /* Time to notify. */ _svmm_mutex_lock (fat_lock->fatlock.mutex); _svmm_cond_broadcast (fat_lock->fatlock.notification_cond); _svmm_mutex_unlock (); } } end: _svmf_stopping_java (env); } /* ---------------------------------------------------------------------- Java_java_lang_VMObject_wait ---------------------------------------------------------------------- */ /* * Class: java_lang_VMObject * Method: wait * Signature: (Ljava/lang/Object;JI)V */ JNIEXPORT static void JNICALL Java_java_lang_VMObject_wait (JNIEnv *_env, jclass class, jobject o, jlong ms, jint ns) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); _svmt_JavaVM *vm = env->vm; _svmf_resuming_java (env); { _svmt_object_instance *instance = *o; _svmt_word lockword = instance->lockword; /* If it is a thinlock, we must inflate it first. */ if (_svmf_lockword_is_thin (lockword)) { if (_svmf_lockword_get_thinlock_id (lockword) != env->thread.thinlock_id) { _svmf_error_IllegalMonitorStateException (env); goto end; } _svmf_inflate_lock_no_exception (env, instance); lockword = instance->lockword; } assert (!_svmf_lockword_is_thin (lockword)); /* handle contention - we need to signal *at least* threads that * waited for lock we've just inflated, but we do it for all anyway */ _svmm_mutex_lock (env->contention.owner.mutex); _svmf_handle_contention (env, instance); _svmm_mutex_unlock (); /* wait on the fat lock */ { jint fat_id = _svmf_lockword_get_fatlock_index (lockword); _svmt_JNIEnv *fat_lock = vm->threads.array[fat_id]; jboolean throw_interrupted_requested = JNI_FALSE; assert (fat_id != 0); assert (fat_lock != NULL); if (fat_lock->fatlock.owner != env) { _svmf_error_IllegalMonitorStateException (env); goto end; } /* prepare to sleep... */ _svmf_stopping_java (env); _svmm_mutex_lock (fat_lock->fatlock.mutex); /* in case of Thread.interrupt() put info that we're sleeping */ { _svmt_word old_status, new_status; _svmm_debug_synchronization (env, "before interrupted_status (%d,%d) on fatlock (%d)", env->interrupted_status, env->interrupted_status >> 16, fat_lock->thread.id, NULL); /* assert ((env->interrupted_status >> 16) == 0); */ do { new_status = old_status = env->interrupted_status; new_status |= fat_id << 16; new_status |= SVM_THREAD_INTERRUPTIBLE_ON_FAT_LOCK; new_status &= ~SVM_THREAD_THROW_INTERRUPTED; _svmm_debug_synchronization (env, "before wait interrupted_status (%d,%d)", old_status, new_status, NULL, NULL); } while (!_svmm_compare_and_swap (env->interrupted_status, old_status, new_status)); } /* Time to wait. */ { jint recursive_count = fat_lock->fatlock.recursive_count; fat_lock->fatlock.recursive_count = 0; fat_lock->fatlock.owner = NULL; fat_lock->fatlock.threads_waiting_no++; assert (fat_lock->fatlock.threads_waiting_no >= 1); _svmm_cond_broadcast (fat_lock->fatlock.cond); if (ms == 0 && ns == 0) { _svmm_cond_wait (fat_lock->fatlock.notification_cond, fat_lock->fatlock.mutex); } else { /* The following code is unfortunately platform dependent. You will have to find some function like gettimeofday() that returns the current time as precisely as possible. In the worst case, simply use the quite imprecise ISO C time() function. */ struct timeval now; struct timespec timeout; gettimeofday (&now, NULL); timeout.tv_sec = now.tv_sec; timeout.tv_nsec = now.tv_usec * 1000; timeout.tv_sec = timeout.tv_sec + (ms / 1000); timeout.tv_nsec = timeout.tv_nsec + (ms % 1000) * 1000 * 1000 + ns; /* Watch for overflow of timeout.tv_nsec... OK; I assume that tv_nsec has at least 32 bits (signed or not, I don't care), a reasonable assumption given that it must be able to hold the value 999999999. */ if (timeout.tv_nsec >= 1000000000L) { timeout.tv_sec++; timeout.tv_nsec -= 1000000000L; } /* I don't care about overflow of timeout.tv_sec. */ for (;;) { struct timeval tvnow; struct timespec tsnow; /* Don't count on returned value. According to the * OpenGroup specs it should _never_ return EINTR ! * Check interrupted_status flag and timeout instead */ _svmm_cond_timedwait (fat_lock->fatlock.notification_cond, fat_lock->fatlock.mutex, timeout); /* are we sure we should wake up? * have we been interrupted or the time passed? */ { _svmt_word old_status, new_status; jboolean time_passed = JNI_FALSE; gettimeofday (&tvnow, NULL); tsnow.tv_sec = tvnow.tv_sec; tsnow.tv_nsec = tvnow.tv_usec * 1000; if (tsnow.tv_sec > timeout.tv_sec || ((tsnow.tv_sec == timeout.tv_sec) && (tsnow.tv_nsec >= timeout.tv_nsec))) { time_passed = JNI_TRUE; } do { new_status = old_status = env->interrupted_status; if (old_status & SVM_THREAD_THROW_INTERRUPTED) { new_status &= ~SVM_THREAD_INTERRUPTIBLE_ON_FAT_LOCK; new_status &= ~SVM_THREAD_THROW_INTERRUPTED; new_status &= 0xffff; /* remove fat_id */ } else if (time_passed) { new_status &= ~SVM_THREAD_INTERRUPTIBLE_ON_FAT_LOCK; new_status &= 0xffff; /* remove fat_id */ } } while (!_svmm_compare_and_swap (env->interrupted_status, old_status, new_status)); _svmm_debug_synchronization (env, "after wait interrupted_status (%d,%d)", old_status, new_status, NULL, NULL); if (old_status & SVM_THREAD_THROW_INTERRUPTED) { /* we've been interrupt()ed */ throw_interrupted_requested = JNI_TRUE; break; } if (time_passed) { break; } } } } /* wait until no other thread owns the fat lock */ while (fat_lock->fatlock.recursive_count != 0 && fat_lock->fatlock.owner != env) { _svmm_cond_wait (fat_lock->fatlock.cond, fat_lock->fatlock.mutex); } fat_lock->fatlock.recursive_count = recursive_count; fat_lock->fatlock.owner = env; fat_lock->fatlock.threads_waiting_no--; } _svmm_mutex_unlock (); _svmf_resuming_java (env); /* throw an InterruptedException if we've been interrupt()ed */ if (throw_interrupted_requested == JNI_TRUE) { _svmf_error_InterruptedException (env); } } } end: _svmf_stopping_java (env); } /* ---------------------------------------------------------------------- Java_java_lang_VMObject_clone ---------------------------------------------------------------------- */ /* * Class: java_lang_VMObject * Method: clone * Signature: (Ljava/lang/Cloneable;)Ljava/lang/Object; */ JNIEXPORT static jobject JNICALL Java_java_lang_VMObject_clone (JNIEnv *_env, jclass class, jobject obj) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); jobject clone = NULL; _svmf_resuming_java (env); { clone = _svmf_get_jni_frame_native_local (env); _svmf_clone_instance (env, obj, clone); } _svmf_stopping_java (env); return clone; }