/** * Attempt to gain the ownership over monitor without blocking. * * @param[in] monitor object where monitor is located */ IDATA VMCALL jthread_monitor_try_enter(jobject monitor) { assert(monitor); hythread_suspend_disable(); hythread_thin_monitor_t *lockword = vm_object_get_lockword_addr(monitor); IDATA status = hythread_thin_monitor_try_enter(lockword); hythread_suspend_enable(); if (status == TM_ERROR_NONE && ti_is_enabled()) { jthread_add_owned_monitor(monitor); } return status; } // jthread_monitor_try_enter
/** * Releases the ownership over monitor. * * @param[in] monitor monitor * @sa JNI::MonitorExit() */ IDATA VMCALL jthread_monitor_exit(jobject monitor) { assert(monitor); hythread_suspend_disable(); hythread_thin_monitor_t *lockword = vm_object_get_lockword_addr(monitor); IDATA status = hythread_thin_monitor_exit(lockword); hythread_suspend_enable(); if (status == TM_ERROR_NONE && ti_is_enabled()) { jthread_remove_owned_monitor(monitor); } if (status == TM_ERROR_ILLEGAL_STATE) { jthread_throw_exception("java/lang/IllegalMonitorStateException", "Illegal monitor state"); } return status; } // jthread_monitor_exit
/** * Detaches current thread from VM. */ jint vm_detach(jobject java_thread) { assert(hythread_is_suspend_enabled()); hythread_t native_thread = jthread_get_native_thread(java_thread); assert(native_thread); vm_thread_t p_vm_thread = jthread_get_vm_thread(native_thread); assert(p_vm_thread); // Send Thread End event if(jvmti_should_report_event(JVMTI_EVENT_THREAD_END)) { jvmti_send_thread_start_end_event(p_vm_thread, 0); } // change java_status for native thread native_thread->java_status = TM_STATUS_ALLOCATED; if (native_thread == hythread_self()) { // Notify GC about thread detaching. // FIXME - GC notify detach thread works for current thread only gc_thread_kill(&p_vm_thread->_gc_private_information); } if (ti_is_enabled()) { apr_status_t UNREF status; status = port_vmem_free( p_vm_thread->jvmti_thread.jvmti_jit_breakpoints_handling_buffer, TM_JVMTI_MAX_BUFFER_SIZE); assert(status == APR_SUCCESS); } // Destroy current VM_thread pool and zero VM_thread structure jthread_deallocate_vm_thread_pool(p_vm_thread); return JNI_OK; }
/** * Gains the ownership over monitor. * * Current thread blocks if the specified monitor is owned by other thread. * * @param[in] monitor object where monitor is located * @sa JNI::MonitorEnter() */ IDATA VMCALL jthread_monitor_enter(jobject monitor) { IDATA state; hythread_t native_thread; apr_time_t enter_begin; assert(monitor); hythread_suspend_disable(); hythread_thin_monitor_t *lockword = vm_object_get_lockword_addr(monitor); IDATA status = hythread_thin_monitor_try_enter(lockword); if (status != TM_ERROR_EBUSY) { goto entered; } #ifdef LOCK_RESERVATION // busy unreserve lock before blocking and inflating while (TM_ERROR_NONE != hythread_unreserve_lock(lockword)) { hythread_yield(); hythread_safe_point(); hythread_exception_safe_point(); lockword = vm_object_get_lockword_addr(monitor); } status = hythread_thin_monitor_try_enter(lockword); if (status != TM_ERROR_EBUSY) { goto entered; } #endif //LOCK_RESERVATION native_thread = hythread_self(); hythread_thread_lock(native_thread); state = hythread_get_state(native_thread); state &= ~TM_THREAD_STATE_RUNNABLE; state |= TM_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER; status = hythread_set_state(native_thread, state); assert(status == TM_ERROR_NONE); hythread_thread_unlock(native_thread); // should be moved to event handler if (ti_is_enabled()) { enter_begin = apr_time_now(); int disable_count = hythread_reset_suspend_disable(); jthread_set_owned_monitor(monitor); if(jvmti_should_report_event(JVMTI_EVENT_MONITOR_CONTENDED_ENTER)) { jvmti_send_contended_enter_or_entered_monitor_event(monitor, 1); } hythread_set_suspend_disable(disable_count); } // busy wait and inflate // reload pointer after safepoints lockword = vm_object_get_lockword_addr(monitor); while ((status = hythread_thin_monitor_try_enter(lockword)) == TM_ERROR_EBUSY) { hythread_safe_point(); hythread_exception_safe_point(); lockword = vm_object_get_lockword_addr(monitor); if (hythread_is_fat_lock(*lockword)) { status = hythread_thin_monitor_enter(lockword); if (status != TM_ERROR_NONE) { hythread_suspend_enable(); assert(0); return status; } goto contended_entered; } hythread_yield(); } assert(status == TM_ERROR_NONE); if (!hythread_is_fat_lock(*lockword)) { hythread_inflate_lock(lockword); } // do all ti staff here contended_entered: if (ti_is_enabled()) { int disable_count = hythread_reset_suspend_disable(); if(jvmti_should_report_event(JVMTI_EVENT_MONITOR_CONTENDED_ENTERED)) { jvmti_send_contended_enter_or_entered_monitor_event(monitor, 0); } hythread_set_suspend_disable(disable_count); // should be moved to event handler jvmti_thread_t jvmti_thread = jthread_get_jvmti_thread(hythread_self()); jvmti_thread->blocked_time += apr_time_now() - enter_begin; } hythread_thread_lock(native_thread); state = hythread_get_state(native_thread); state &= ~TM_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER; state |= TM_THREAD_STATE_RUNNABLE; status = hythread_set_state(native_thread, state); assert(status == TM_ERROR_NONE); hythread_thread_unlock(native_thread); entered: if (ti_is_enabled()) { jthread_add_owned_monitor(monitor); } hythread_suspend_enable(); return TM_ERROR_NONE; } // jthread_monitor_enter
/** * Wait on the <code>object</code>'s monitor with the specified timeout. * * This function instructs the current thread to be scheduled off * the processor and wait on the monitor until the following occurs: * <UL> * <LI>another thread invokes <code>thread_notify(object)</code> * and VM chooses this thread to wake up; * <LI>another thread invokes <code>thread_notifyAll(object);</code> * <LI>another thread invokes <code>thread_interrupt(thread);</code> * <LI>real time elapsed from the waiting begin is * greater or equal the timeout specified. * </UL> * * @param[in] monitor object where monitor is located * @param[in] millis time to wait (in milliseconds) * @param[in] nanos time to wait (in nanoseconds) * @sa java.lang.Object.wait() */ IDATA VMCALL jthread_monitor_timed_wait(jobject monitor, jlong millis, jint nanos) { assert(monitor); hythread_suspend_disable(); hythread_t native_thread = hythread_self(); hythread_thin_monitor_t *lockword = vm_object_get_lockword_addr(monitor); if (!hythread_is_fat_lock(*lockword)) { if (!hythread_owns_thin_lock(native_thread, *lockword)) { CTRACE(("ILLEGAL_STATE wait %x\n", lockword)); hythread_suspend_enable(); return TM_ERROR_ILLEGAL_STATE; } hythread_inflate_lock(lockword); } apr_time_t wait_begin; if (ti_is_enabled()) { int disable_count = hythread_reset_suspend_disable(); jthread_set_wait_monitor(monitor); jthread_set_owned_monitor(monitor); if(jvmti_should_report_event(JVMTI_EVENT_MONITOR_WAIT)) { jvmti_send_wait_monitor_event(monitor, (jlong) millis); } if(jvmti_should_report_event(JVMTI_EVENT_MONITOR_CONTENDED_ENTER)) { jvmti_send_contended_enter_or_entered_monitor_event(monitor, 1); } hythread_set_suspend_disable(disable_count); // should be moved to event handler wait_begin = apr_time_now(); jthread_remove_owned_monitor(monitor); } hythread_thread_lock(native_thread); IDATA state = hythread_get_state(native_thread); state &= ~TM_THREAD_STATE_RUNNABLE; state |= TM_THREAD_STATE_WAITING | TM_THREAD_STATE_IN_MONITOR_WAIT; if ((millis > 0) || (nanos > 0)) { state |= TM_THREAD_STATE_WAITING_WITH_TIMEOUT; } else { state |= TM_THREAD_STATE_WAITING_INDEFINITELY; } IDATA status = hythread_set_state(native_thread, state); assert(status == TM_ERROR_NONE); hythread_thread_unlock(native_thread); status = hythread_thin_monitor_wait_interruptable(lockword, millis, nanos); hythread_thread_lock(native_thread); state = hythread_get_state(native_thread); if ((millis > 0) || (nanos > 0)) { state &= ~TM_THREAD_STATE_WAITING_WITH_TIMEOUT; } else { state &= ~TM_THREAD_STATE_WAITING_INDEFINITELY; } state &= ~(TM_THREAD_STATE_WAITING | TM_THREAD_STATE_IN_MONITOR_WAIT); state |= TM_THREAD_STATE_RUNNABLE; hythread_set_state(native_thread, state); hythread_thread_unlock(native_thread); hythread_suspend_enable(); if (ti_is_enabled()) { jthread_add_owned_monitor(monitor); int disable_count = hythread_reset_suspend_disable(); if(jvmti_should_report_event(JVMTI_EVENT_MONITOR_CONTENDED_ENTERED)) { jvmti_send_contended_enter_or_entered_monitor_event(monitor, 0); } if(jvmti_should_report_event(JVMTI_EVENT_MONITOR_WAITED)) { jvmti_send_waited_monitor_event(monitor, ((status == APR_TIMEUP) ? (jboolean) 1 : (jboolean) 0)); } hythread_set_suspend_disable(disable_count); // should be moved to event handler jvmti_thread_t jvmti_thread = jthread_get_jvmti_thread(hythread_self()); jvmti_thread->waited_time += apr_time_now() - wait_begin; } return status; } // jthread_monitor_timed_wait
/** * Attaches thread current thread to VM. */ jint vm_attach(JavaVM * java_vm, JNIEnv ** p_jni_env) { // It seems to be reasonable to have suspend enabled state here. // It is unsafe to perform operations which require suspend disabled // mode until current thread is not attaced to VM. assert(hythread_is_suspend_enabled()); vm_thread_t vm_thread = jthread_self_vm_thread_unsafe(); assert(vm_thread); // if the assertion is false we cannot notify the parent thread // that we started and it would hang in waitloop assert(vm_thread); jint status = jthread_allocate_vm_thread_pool(java_vm, vm_thread); if (status != JNI_OK) { return status; } // Create top level M2N frame. M2nFrame *p_m2n = (M2nFrame *) apr_palloc(vm_thread->pool, sizeof(M2nFrame)); if (!p_m2n) { return JNI_ENOMEM; } // Create local handles. ObjectHandles *p_handles = (ObjectHandles *) apr_palloc(vm_thread->pool, sizeof(ObjectHandlesNew)); if (!p_handles) { return JNI_ENOMEM; } vm_thread->jni_env = (JNIEnv *) apr_palloc(vm_thread->pool, sizeof(JNIEnv_Internal)); if (!vm_thread->jni_env) { return JNI_ENOMEM; } // Initialize JNI environment. JNIEnv_Internal *jni_env = (JNIEnv_Internal *) vm_thread->jni_env; jni_env->functions = &jni_vtable; jni_env->vm = (JavaVM_Internal *) java_vm; jni_env->reserved0 = (void *) 0x1234abcd; *p_jni_env = jni_env; m2n_null_init(p_m2n); m2n_set_last_frame(p_m2n); oh_null_init_handles(p_handles); m2n_set_local_handles(p_m2n, p_handles); m2n_set_frame_type(p_m2n, FRAME_NON_UNWINDABLE); gc_thread_init(&vm_thread->_gc_private_information); if (ti_is_enabled()) { vm_thread->jvmti_thread.owned_monitors_size = TM_INITIAL_OWNED_MONITOR_SIZE; vm_thread->jvmti_thread.owned_monitors = (jobject*)apr_palloc(vm_thread->pool, TM_INITIAL_OWNED_MONITOR_SIZE * sizeof(jobject)); void *addr = NULL; apr_status_t UNREF status = port_vmem_allocate(&addr, TM_JVMTI_MAX_BUFFER_SIZE, PORT_VMEM_MODE_READ | PORT_VMEM_MODE_WRITE | PORT_VMEM_MODE_EXECUTE); assert(status == APR_SUCCESS); vm_thread->jvmti_thread.jvmti_jit_breakpoints_handling_buffer = reinterpret_cast<jbyte *>(addr); assert(VM_Global_State::loader_env->TI); VM_Global_State::loader_env->TI->reportLocally(); } ((hythread_t)vm_thread)->java_status = TM_STATUS_INITIALIZED; assert(hythread_is_suspend_enabled()); return JNI_OK; }