jvmtiError JNICALL jvmtiGetLocalLong(jvmtiEnv* env, jthread thread, jint depth, jint slot, jlong* value_ptr) { TRACE("GetLocalLong called"); SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_access_local_variables); // check error condition: JVMTI_ERROR_INVALID_THREAD // check error condition: JVMTI_ERROR_THREAD_NOT_ALIVE // check error condition: JVMTI_ERROR_ILLEGAL_ARGUMENT // check error condition: JVMTI_ERROR_NULL_POINTER jvmtiError err = GetLocal_checkArgs(env, &thread, depth, slot, value_ptr); if (err != JVMTI_ERROR_NONE) return err; bool thread_suspended = false; // Suspend thread before getting stacks vm_thread_t vm_thread; if (NULL != thread) { // Check that this thread is not current vm_thread = jthread_get_vm_thread_ptr_safe(thread); if (vm_thread != p_TLS_vmthread) { IDATA UNREF status = hythread_suspend_other((hythread_t)vm_thread); assert(TM_ERROR_NONE == status); thread_suspended = true; } } else vm_thread = p_TLS_vmthread; if (interpreter_enabled()) // check error condition: JVMTI_ERROR_INVALID_SLOT // check error condition: JVMTI_ERROR_OPAQUE_FRAME // check error condition: JVMTI_ERROR_NO_MORE_FRAMES // TODO: check error condition: JVMTI_ERROR_TYPE_MISMATCH err = interpreter.interpreter_ti_getLocal64(env, vm_thread, depth, slot, value_ptr); else { GET_JIT_FRAME_CONTEXT; tmn_suspend_disable(); OpenExeJpdaError result = jit->get_local_var(method, jfc, slot, VM_DATA_TYPE_INT64, value_ptr); si_free(si); tmn_suspend_enable(); err = jvmti_translate_jit_error(result); } if (thread_suspended) hythread_resume((hythread_t)vm_thread); return err; }
/** * Used lockword * Thin monitor functions used java monitor. */ IDATA VMCALL hythread_unreserve_lock(hythread_thin_monitor_t *lockword_ptr) { U_32 lockword = *lockword_ptr; U_32 lockword_new; uint16 lock_id; hythread_t owner; IDATA status; I_32 append; // trylock used to prevent cyclic suspend deadlock // the java_monitor_enter calls safe_point between attempts. /*status = port_mutex_trylock(&TM_LOCK); if (status !=TM_ERROR_NONE) { return status; }*/ if (IS_FAT_LOCK(lockword)) { return TM_ERROR_NONE; } lock_id = THREAD_ID(lockword); owner = hythread_get_thread(lock_id); CTRACE(("Unreserved other %d \n", ++unreserve_count/*, vm_get_object_class_name(lockword_ptr-1)*/)); if (!IS_RESERVED(lockword) || IS_FAT_LOCK(lockword)) { // port_mutex_unlock(&TM_LOCK); return TM_ERROR_NONE; } // suspend owner if (owner) { assert(owner); assert(hythread_get_id(owner) == lock_id); assert(owner != hythread_self()); if(owner->state & (TM_THREAD_STATE_TERMINATED | TM_THREAD_STATE_WAITING | TM_THREAD_STATE_WAITING_INDEFINITELY | TM_THREAD_STATE_WAITING_WITH_TIMEOUT | TM_THREAD_STATE_SLEEPING | TM_THREAD_STATE_PARKED | TM_THREAD_STATE_SUSPENDED | TM_THREAD_STATE_IN_MONITOR_WAIT)) { append = 0; } else { append = RESERVED_BITMASK; } status=hythread_suspend_other(owner); if (status !=TM_ERROR_NONE) { return status; } } else { append = 0; } if(!tm_properties || !tm_properties->use_soft_unreservation) { append = RESERVED_BITMASK; } // prepare new unreserved lockword and try to CAS it with old one. while (IS_RESERVED(lockword)) { assert(!IS_FAT_LOCK(lockword)); CTRACE(("unreserving lock")); if (RECURSION(lockword) != 0) { lockword_new = (lockword | RESERVED_BITMASK); assert(RECURSION(lockword) > 0); assert(RECURSION(lockword_new) > 0); RECURSION_DEC(&lockword_new, lockword_new); } else { lockword_new = (lockword | append); lockword_new = lockword_new & 0x0000ffff; } if (lockword == apr_atomic_cas32 (((volatile apr_uint32_t*) lockword_ptr), (apr_uint32_t) lockword_new, lockword)) { CTRACE(("unreserved lock")); break; } lockword = *lockword_ptr; } // resume owner if (owner) { hythread_yield_other(owner); hythread_resume(owner); } /* status = port_mutex_unlock(&TM_LOCK);*/ // Gregory - This lock, right after it was unreserved, may be // inflated by another thread and therefore instead of recursion // count and reserved flag it will have the fat monitor ID. The // assertion !IS_RESERVED(lockword) fails in this case. So it is // necessary to check first that monitor is not fat. // To avoid race condition between checking two different // conditions inside of assert, the lockword contents has to be // loaded before checking. // lockword = *lockword_ptr; // assert(IS_FAT_LOCK(lockword) || !IS_RESERVED(lockword)); return TM_ERROR_NONE; }
/** * General function to set value of local variable. * @param var_type type of the local variable * @param p_value pointer to the new variable value */ static jvmtiError set_local(jvmtiEnv* env, jthread thread, jint depth, jint slot, VM_Data_Type var_type, void* p_value) { SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_access_local_variables); // check error condition: JVMTI_ERROR_INVALID_THREAD // check error condition: JVMTI_ERROR_THREAD_NOT_ALIVE // check error condition: JVMTI_ERROR_ILLEGAL_ARGUMENT jvmtiError err = GetLocal_checkArgs(env, &thread, depth, slot, p_value); if (err != JVMTI_ERROR_NONE) return err; // check error condition: JVMTI_ERROR_INVALID_OBJECT if (VM_DATA_TYPE_CLASS == var_type && ! is_valid_object(env, *(jobject*) p_value)) return JVMTI_ERROR_INVALID_OBJECT; bool thread_suspended = false; // Suspend thread before getting stacks vm_thread_t vm_thread; if (NULL != thread) { // Check that this thread is not current vm_thread = jthread_get_vm_thread_ptr_safe(thread); if (vm_thread != p_TLS_vmthread) { IDATA UNREF status = hythread_suspend_other((hythread_t)vm_thread); assert(TM_ERROR_NONE == status); thread_suspended = true; } } else vm_thread = p_TLS_vmthread; if (interpreter_enabled()) { // TODO: check error condition: JVMTI_ERROR_INVALID_SLOT // TODO: check error condition: JVMTI_ERROR_TYPE_MISMATCH // TODO: check error condition: JVMTI_ERROR_OPAQUE_FRAME // TODO: check error condition: JVMTI_ERROR_NO_MORE_FRAMES switch (var_type) { case VM_DATA_TYPE_CLASS: err = interpreter.interpreter_ti_setObject(env, vm_thread, depth, slot, *(jobject*) p_value); break; case VM_DATA_TYPE_INT32: case VM_DATA_TYPE_F4: err = interpreter.interpreter_ti_setLocal32(env, vm_thread, depth, slot, *(int*) p_value); break; case VM_DATA_TYPE_INT64: case VM_DATA_TYPE_F8: err = interpreter.interpreter_ti_setLocal64(env, vm_thread, depth, slot, *(int64*) p_value); break; default: DIE(("Error: unrecognized local variable type")); } } else { GET_JIT_FRAME_CONTEXT; tmn_suspend_disable(); OpenExeJpdaError result; switch (var_type) { case VM_DATA_TYPE_CLASS: if (NULL != *(jobject*) p_value) result = jit->set_local_var(method, jfc, slot, VM_DATA_TYPE_CLASS, &(*(ObjectHandle*) p_value)->object); else { ManagedObject *n = (ManagedObject *)VM_Global_State::loader_env->managed_null; result = jit->set_local_var(method, jfc, slot, VM_DATA_TYPE_CLASS, &n); } break; case VM_DATA_TYPE_INT32: case VM_DATA_TYPE_F4: case VM_DATA_TYPE_INT64: case VM_DATA_TYPE_F8: result = jit->set_local_var(method, jfc, slot, var_type, p_value); break; default: DIE(("Error: unrecognized local variable type")); } si_free(si); tmn_suspend_enable(); err = jvmti_translate_jit_error(result); } if (thread_suspended) hythread_resume((hythread_t)vm_thread); return err; }
int test_hythread_thread_suspend(void){ void **args; hythread_t thread = NULL; hythread_thin_monitor_t lock; hythread_thin_monitor_t monitor; IDATA status; int i; // create monitors status = hythread_thin_monitor_create(&lock); tf_assert_same(status, TM_ERROR_NONE); status = hythread_thin_monitor_create(&monitor); tf_assert_same(status, TM_ERROR_NONE); // alloc and set thread start procedure args args = (void**)calloc(3, sizeof(void*)); args[0] = &lock; args[1] = &monitor; args[2] = 0; // create thread hythread_suspend_disable(); status = hythread_thin_monitor_enter(&lock); tf_assert_same(status, TM_ERROR_NONE); hythread_suspend_enable(); status = hythread_create(&thread, 0, 0, 0, (hythread_entrypoint_t)start_proc, args); tf_assert_same(status, TM_ERROR_NONE); // waiting start of tested thread hythread_suspend_disable(); status = hythread_thin_monitor_wait(&lock); tf_assert_same(status, TM_ERROR_NONE); status = hythread_thin_monitor_exit(&lock); tf_assert_same(status, TM_ERROR_NONE); hythread_suspend_enable(); // suspend tested thread status = hythread_suspend_other(thread); tf_assert_same(status, TM_ERROR_NONE); // notify tested thread hythread_suspend_disable(); status = hythread_thin_monitor_enter(&monitor); tf_assert_same(status, TM_ERROR_NONE); status = hythread_thin_monitor_notify_all(&monitor); tf_assert_same(status, TM_ERROR_NONE); status = hythread_thin_monitor_exit(&monitor); tf_assert_same(status, TM_ERROR_NONE); hythread_suspend_enable(); // check tested argument for(i = 0; i < 1000; i++) { tf_assert_same(args[2], 0); hythread_sleep(1); } // resume thread hythread_resume(thread); test_thread_join(thread, 1); tf_assert_same((IDATA)args[2], 1); return 0; }