/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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_fat_lock *fat_lock = vm->fat_locks.array[fat_id]; if (fat_lock->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->threads_waiting_no, fat_lock->id, NULL, NULL); /* Time to notify. */ _svmm_mutex_lock (fat_lock->mutex); _svmm_cond_signal (fat_lock->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_fat_lock *fat_lock = vm->fat_locks.array[fat_id]; if (fat_lock->owner != env) { _svmf_error_IllegalMonitorStateException (env); goto end; } _svmm_debug_synchronization (env, "will notifyAll %d threads on fatlock (%d) we own", fat_lock->threads_waiting_no, fat_lock->id, NULL, NULL); /* Time to notify. */ _svmm_mutex_lock (fat_lock->mutex); _svmm_cond_broadcast (fat_lock->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; jboolean just_inflated = JNI_FALSE; /* 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; } #ifdef STATISTICS env->vm->total_lock_inflations_in_wait_count++; #endif _svmf_inflate_lock_no_exception (env, instance, 0); lockword = instance->lockword; just_inflated = JNI_TRUE; } assert (!_svmf_lockword_is_thin (lockword)); /* First, handle the any pending contention on a former thinlock. * We need to signal *at least* threads that waited for lock we have * just inflated, but we do it for all contending threads anyway */ if ((env->contention.owner.flag) && (just_inflated)) { _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_fat_lock *fat_lock = vm->fat_locks.array[fat_id]; jboolean throw_interrupted_requested = JNI_FALSE; jboolean might_need_deflating = JNI_FALSE; assert (fat_id != 0); assert (fat_lock != NULL); if (fat_lock->owner != env) { _svmf_error_IllegalMonitorStateException (env); goto end; } #ifdef STATISTICS vm->total_lock_waits_count++; #endif /* prepare to sleep... */ _svmf_stopping_java (env); _svmm_mutex_lock (fat_lock->mutex); /* in case of Thread.interrupt() put info that we're sleeping */ { _svmt_word old_status, new_status; /* Why does this assertion fail sometimes? It should not! * 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; } while (!_svmm_compare_and_swap (env->interrupted_status, old_status, new_status)); } /* Time to wait. */ { jint recursive_count = fat_lock->recursive_count; fat_lock->recursive_count = 0; fat_lock->owner = NULL; fat_lock->threads_waiting_no++; assert (fat_lock->threads_waiting_no >= 1); _svmm_cond_broadcast (fat_lock->cond); if (ms == 0 && ns == 0) { _svmm_cond_wait (fat_lock->notification_cond, fat_lock->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->notification_cond, fat_lock->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)); 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->recursive_count != 0 && fat_lock->owner != env) { _svmm_cond_wait (fat_lock->cond, fat_lock->mutex); } fat_lock->recursive_count = recursive_count; fat_lock->owner = env; fat_lock->threads_waiting_no--; /* Be smart. If at this point we know deflation is not * feasible, it will not be feasible later, because while * we're holding the monitor these counters may only increase */ if ((fat_lock->threads_waiting_no == 0) && (fat_lock->threads_blocked_no + fat_lock->threads_to_come_no <= 1)) { might_need_deflating = JNI_TRUE; } } _svmm_mutex_unlock (); _svmf_resuming_java (env); /* GC could have moved things around */ instance = *o; lockword = instance->lockword; if (might_need_deflating) { jint deflated = JNI_FALSE; /* we might need to deflate the lock */ _svmm_mutex_lock (fat_lock->mutex); _svmm_cond_broadcast (fat_lock->cond); /* Note: we need to check the condition again, as some * new threads might got blocked on this monitor. */ if ((fat_lock->threads_waiting_no == 0) && (fat_lock->threads_blocked_no + fat_lock->threads_to_come_no <= 1)) { #ifdef STATISTICS env->vm->total_lock_deflations_in_wait_count++; #endif _svmf_deflate_lock_no_exception (env, fat_lock, instance); deflated = JNI_TRUE; } _svmm_mutex_unlock (); if (deflated == JNI_TRUE) { /* give fatlock back to the free list */ _svmf_put_fatlock_fast (env, fat_lock); } } /* 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; }