/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define dump_wait(msg) /* do { _svmt_JNIEnv *current = vm->wait.list; \ _svmf_printf(env, stderr, "WAIT_DUMP(%d) %s: ", env->thread.id, msg); \ while (current) { \ _svmf_printf(env, stderr, "(%d,%d) ", current->thread.id, \ *(current->wait.jobject)); \ current = current->wait.next; \ } \ _svmf_printf(env, stderr, "\n"); fflush(NULL); \ } while(0) */ /* ---------------------------------------------------------------------- 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 SVM_UNUSED, 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; } } else /* 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 threads on instance (%d) we own", instance, NULL, NULL, NULL); /* Time to notify. */ _svmm_mutex_lock (vm->wait.mutex); { _svmt_JNIEnv *current = vm->wait.list; dump_wait("notify"); while (current) { if (*(current->wait.jobject) == instance) { _svmm_cond_signal (current->wait.cond); _svmm_debug_synchronization (env, "notifying thread (%d) on instance (%d) we own", current->thread.id, instance, NULL, NULL); goto release_end; /* only notify the first one */ } current = current->wait.next; } } release_end: _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 SVM_UNUSED, 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; } } else /* 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 threads on instance (%d) we own", instance, NULL, NULL, NULL); /* Time to notify. */ _svmm_mutex_lock (vm->wait.mutex); { _svmt_JNIEnv *current; dump_wait("notifyAll"); for (current = vm->wait.list; current; current = current->wait.next) { if (*(current->wait.jobject) == instance) { _svmm_cond_signal (current->wait.cond); _svmm_debug_synchronization (env, "notifying thread (%d) on instance (%d) we own", current->thread.id, instance, NULL, NULL); } } } _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 SVM_UNUSED, jobject o, jlong ms, jint ns) { _svmt_JNIEnv *env = _svmf_cast_svmt_JNIEnv (_env); _svmt_JavaVM *vm = env->vm; _svmm_profile_in (wait); _svmf_resuming_java (env); { _svmt_object_instance *instance = *o; _svmt_word lockword = instance->lockword; jboolean error = JNI_FALSE; _svmt_word recursive_count = 0; /* Set to make compiler happy. */ _svmt_word extra_bits = _svmf_lockword_get_extra_bits (lockword); _svmm_mutex_lock (vm->wait.mutex); /* Check ownership, save recursion count and free the monitor, * setting wait flag on it. */ if (_svmf_lockword_is_thin (lockword)) { if (_svmf_lockword_get_thinlock_id (lockword) != env->thread.thinlock_id) { _svmf_error_IllegalMonitorStateException (env); error = JNI_TRUE; goto error; } recursive_count = _svmf_lockword_get_thinlock_recursive_count (lockword); instance->lockword = extra_bits; } else /* Fat lock */ { jint fat_id = _svmf_lockword_get_fatlock_index (lockword); _svmt_fat_lock *fat_lock = vm->fat_locks.array[fat_id]; jboolean deflated = JNI_FALSE; assert (fat_lock != NULL); if (fat_lock->owner != env) { _svmf_error_IllegalMonitorStateException (env); error = JNI_TRUE; goto error; } _svmm_mutex_lock (fat_lock->mutex); /* We store recursive count as for thinlock */ recursive_count = fat_lock->recursive_count - 1; fat_lock->recursive_count = 0; fat_lock->owner = NULL; /* We might need to deflate before unlocking. */ if ((fat_lock->threads_blocked_no + fat_lock->threads_to_come_no <= 1)) { _svmm_cond_broadcast (fat_lock->cond); _svmf_deflate_lock_no_exception (env, fat_lock, instance); deflated = JNI_TRUE; } else { /* Notify one of blocked threads. */ _svmm_cond_signal (fat_lock->cond); } _svmm_mutex_unlock (); if (deflated == JNI_TRUE) { _svmf_put_fatlock_fast (env, fat_lock); } } /* End of 'Fat lock' */ /* Always handle contention, if there is any. */ if (env->contention.owner.flag) { jint status; _svmm_profile_in (contention_handling); _svmm_mutex_lock (env->contention.owner.mutex); status = _svmf_handle_contention (env, instance); _svmm_mutex_unlock (); _svmm_profile_out (contention_handling); if (status != JNI_OK) { _svmf_error_OutOfMemoryError (env); error = JNI_TRUE; goto error; } } error: _svmm_mutex_unlock (); if (error == JNI_TRUE) { goto end; } /* Save instance, before we go to stop java. */ *(env->wait.jobject) = instance; /* We transition to stopped java w/o holding any mutexes. */ _svmf_stopping_java (env); _svmm_mutex_lock (vm->wait.mutex); /* _svmf_printf (env, stderr, "HERE(%d) 111 going to wait() on instance (%d)\n", env->thread.id, instance); fflush (NULL); */ /* Register and wait */ dump_wait("beforeRegister"); env->wait.next = vm->wait.list; if (vm->wait.list != NULL) { assert (vm->wait.list->wait.prev == NULL); vm->wait.list->wait.prev = env; } env->wait.prev = NULL; vm->wait.list = env; dump_wait("afterRegister"); if (ms == 0 && ns == 0) { _svmm_profile_out (wait); /* Why don't we account for being Interrupt()ed here?!? */ /* _svmf_printf (env, stderr, "HERE(%d) 222222222222222\n", env->thread.id); fflush (NULL); */ _svmm_cond_wait (env->wait.cond, vm->wait.mutex); _svmm_profile_in (wait); } 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. */ { 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_profile_out (wait); /* _svmf_printf (env, stderr, "HERE(%d) 3333333333333333\n", env->thread.id); fflush (NULL); */ _svmm_cond_timedwait (env->wait.cond, vm->wait.mutex, timeout); _svmm_profile_in (wait); } } /* Unregister */ dump_wait("beforeUnregister"); if (env->wait.next != NULL) { env->wait.next->wait.prev = env->wait.prev; } if (env->wait.prev != NULL) { env->wait.prev->wait.next = env->wait.next; } else { /* wait.prev is NULL, save first element pointer */ assert (vm->wait.list == env); vm->wait.list = env->wait.next; } dump_wait("afterUnregister"); _svmm_mutex_unlock (); _svmf_resuming_java (env); /* Restore instance in case GC happened. */ instance = *(env->wait.jobject); *(env->wait.jobject) = NULL; if (_svmf_enter_object_monitor (env, instance) == JNI_OK) { lockword = instance->lockword; if (_svmf_lockword_is_thin (lockword)) { instance->lockword = _svmf_lockword_thinlock (env->thread.thinlock_id, recursive_count, _svmf_lockword_get_extra_bits (lockword)); } else { jint fat_id = _svmf_lockword_get_fatlock_index (lockword); _svmt_fat_lock *fat_lock = vm->fat_locks.array[fat_id]; assert (fat_lock != NULL); /* The recursive count was stored as for thinlock. */ fat_lock->recursive_count = recursive_count + 1; } } else { _svmm_fatal_error ("impossible control flow"); } } end: _svmf_stopping_java (env); _svmm_profile_out (wait); } /* ---------------------------------------------------------------------- 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 SVM_UNUSED, 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; }