8343132: Remove temporary transitions from Virtual thread implementation
Reviewed-by: dholmes, sspitsyn, pchilanomate
This commit is contained in:
parent
2f1ba5ef09
commit
dee0982c60
@ -611,7 +611,6 @@ class methodHandle;
|
||||
do_intrinsic(_notifyJvmtiVThreadEnd, java_lang_VirtualThread, notifyJvmtiEnd_name, void_method_signature, F_RN) \
|
||||
do_intrinsic(_notifyJvmtiVThreadMount, java_lang_VirtualThread, notifyJvmtiMount_name, bool_void_signature, F_RN) \
|
||||
do_intrinsic(_notifyJvmtiVThreadUnmount, java_lang_VirtualThread, notifyJvmtiUnmount_name, bool_void_signature, F_RN) \
|
||||
do_intrinsic(_notifyJvmtiVThreadHideFrames, java_lang_VirtualThread, notifyJvmtiHideFrames_name, bool_void_signature, F_SN) \
|
||||
do_intrinsic(_notifyJvmtiVThreadDisableSuspend, java_lang_VirtualThread, notifyJvmtiDisableSuspend_name, bool_void_signature, F_SN) \
|
||||
\
|
||||
/* support for UnsafeConstants */ \
|
||||
|
@ -398,7 +398,6 @@ class SerializeClosure;
|
||||
template(notifyJvmtiEnd_name, "notifyJvmtiEnd") \
|
||||
template(notifyJvmtiMount_name, "notifyJvmtiMount") \
|
||||
template(notifyJvmtiUnmount_name, "notifyJvmtiUnmount") \
|
||||
template(notifyJvmtiHideFrames_name, "notifyJvmtiHideFrames") \
|
||||
template(notifyJvmtiDisableSuspend_name, "notifyJvmtiDisableSuspend") \
|
||||
template(doYield_name, "doYield") \
|
||||
template(enter_name, "enter") \
|
||||
|
@ -1142,9 +1142,6 @@ JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide);
|
||||
JNIEXPORT void JNICALL
|
||||
JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JVM_VirtualThreadHideFrames(JNIEnv* env, jclass clazz, jboolean hide);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JVM_VirtualThreadDisableSuspend(JNIEnv* env, jclass clazz, jboolean enter);
|
||||
|
||||
|
@ -248,7 +248,6 @@
|
||||
nonstatic_field(JavaThread, _cont_entry, ContinuationEntry*) \
|
||||
nonstatic_field(JavaThread, _unlocked_inflated_monitor, ObjectMonitor*) \
|
||||
JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_VTMS_transition, bool)) \
|
||||
JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_tmp_VTMS_transition, bool)) \
|
||||
JVMTI_ONLY(nonstatic_field(JavaThread, _is_disable_suspend, bool)) \
|
||||
\
|
||||
nonstatic_field(ContinuationEntry, _pin_count, uint32_t) \
|
||||
|
@ -841,7 +841,6 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_notifyJvmtiVThreadEnd:
|
||||
case vmIntrinsics::_notifyJvmtiVThreadMount:
|
||||
case vmIntrinsics::_notifyJvmtiVThreadUnmount:
|
||||
case vmIntrinsics::_notifyJvmtiVThreadHideFrames:
|
||||
case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend:
|
||||
#endif
|
||||
break;
|
||||
|
@ -495,7 +495,6 @@ bool LibraryCallKit::try_to_inline(int predicate) {
|
||||
"notifyJvmtiMount", false, false);
|
||||
case vmIntrinsics::_notifyJvmtiVThreadUnmount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_unmount()),
|
||||
"notifyJvmtiUnmount", false, false);
|
||||
case vmIntrinsics::_notifyJvmtiVThreadHideFrames: return inline_native_notify_jvmti_hide();
|
||||
case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: return inline_native_notify_jvmti_sync();
|
||||
#endif
|
||||
|
||||
@ -2975,29 +2974,6 @@ bool LibraryCallKit::inline_native_notify_jvmti_funcs(address funcAddr, const ch
|
||||
return true;
|
||||
}
|
||||
|
||||
// Always update the temporary VTMS transition bit.
|
||||
bool LibraryCallKit::inline_native_notify_jvmti_hide() {
|
||||
if (!DoJVMTIVirtualThreadTransitions) {
|
||||
return true;
|
||||
}
|
||||
IdealKit ideal(this);
|
||||
|
||||
{
|
||||
// unconditionally update the temporary VTMS transition bit in current JavaThread
|
||||
Node* thread = ideal.thread();
|
||||
Node* hide = _gvn.transform(argument(0)); // hide argument for temporary VTMS transition notification
|
||||
Node* addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_tmp_VTMS_transition_offset()));
|
||||
const TypePtr *addr_type = _gvn.type(addr)->isa_ptr();
|
||||
|
||||
sync_kit(ideal);
|
||||
access_store_at(nullptr, addr, addr_type, hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED);
|
||||
ideal.sync_kit(this);
|
||||
}
|
||||
final_sync(ideal);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Always update the is_disable_suspend bit.
|
||||
bool LibraryCallKit::inline_native_notify_jvmti_sync() {
|
||||
if (!DoJVMTIVirtualThreadTransitions) {
|
||||
|
@ -3941,19 +3941,6 @@ JVM_ENTRY(void, JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean
|
||||
#endif
|
||||
JVM_END
|
||||
|
||||
// Always update the temporary VTMS transition bit.
|
||||
JVM_ENTRY(void, JVM_VirtualThreadHideFrames(JNIEnv* env, jclass clazz, jboolean hide))
|
||||
#if INCLUDE_JVMTI
|
||||
if (!DoJVMTIVirtualThreadTransitions) {
|
||||
assert(!JvmtiExport::can_support_virtual_threads(), "sanity check");
|
||||
return;
|
||||
}
|
||||
assert(!thread->is_in_VTMS_transition(), "sanity check");
|
||||
assert(thread->is_in_tmp_VTMS_transition() != (bool)hide, "sanity check");
|
||||
thread->toggle_is_in_tmp_VTMS_transition();
|
||||
#endif
|
||||
JVM_END
|
||||
|
||||
// Notification from VirtualThread about disabling JVMTI Suspend in a sync critical section.
|
||||
// Needed to avoid deadlocks with JVMTI suspend mechanism.
|
||||
JVM_ENTRY(void, JVM_VirtualThreadDisableSuspend(JNIEnv* env, jclass clazz, jboolean enter))
|
||||
|
@ -929,7 +929,7 @@ class JvmtiClassFileLoadHookPoster : public StackObj {
|
||||
_cached_class_file_ptr = cache_ptr;
|
||||
_has_been_modified = false;
|
||||
|
||||
assert(!_thread->is_in_any_VTMS_transition(), "CFLH events are not allowed in any VTMS transition");
|
||||
assert(!_thread->is_in_VTMS_transition(), "CFLH events are not allowed in VTMS transition");
|
||||
|
||||
_state = JvmtiExport::get_jvmti_thread_state(_thread);
|
||||
if (_state != nullptr) {
|
||||
@ -1091,8 +1091,8 @@ bool JvmtiExport::post_class_file_load_hook(Symbol* h_name,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JavaThread::current()->is_in_any_VTMS_transition()) {
|
||||
return false; // no events should be posted if thread is in any VTMS transition
|
||||
if (JavaThread::current()->is_in_VTMS_transition()) {
|
||||
return false; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
JvmtiClassFileLoadHookPoster poster(h_name, class_loader,
|
||||
@ -1228,8 +1228,8 @@ void JvmtiExport::post_raw_breakpoint(JavaThread *thread, Method* method, addres
|
||||
if (state == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_BREAKPOINT, ("[%s] Trg Breakpoint triggered",
|
||||
@ -1368,8 +1368,8 @@ void JvmtiExport::post_class_load(JavaThread *thread, Klass* klass) {
|
||||
if (state == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_CLASS_LOAD, ("[%s] Trg Class Load triggered",
|
||||
@ -1405,8 +1405,8 @@ void JvmtiExport::post_class_prepare(JavaThread *thread, Klass* klass) {
|
||||
if (state == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_CLASS_PREPARE, ("[%s] Trg Class Prepare triggered",
|
||||
@ -1743,8 +1743,8 @@ void JvmtiExport::post_object_free(JvmtiEnv* env, GrowableArray<jlong>* objects)
|
||||
assert(objects != nullptr, "Nothing to post");
|
||||
|
||||
JavaThread *javaThread = JavaThread::current();
|
||||
if (javaThread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (javaThread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
if (!env->is_enabled(JVMTI_EVENT_OBJECT_FREE)) {
|
||||
return; // the event type has been already disabled
|
||||
@ -1767,8 +1767,8 @@ void JvmtiExport::post_resource_exhausted(jint resource_exhausted_flags, const c
|
||||
|
||||
JavaThread *thread = JavaThread::current();
|
||||
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
log_error(jvmti)("Posting Resource Exhausted event: %s",
|
||||
@ -1810,8 +1810,8 @@ void JvmtiExport::post_method_entry(JavaThread *thread, Method* method, frame cu
|
||||
// for any thread that actually wants method entry, interp_only_mode is set
|
||||
return;
|
||||
}
|
||||
if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_ENTRY, ("[%s] Trg Method Entry triggered %s.%s",
|
||||
JvmtiTrace::safe_get_thread_name(thread),
|
||||
@ -1902,8 +1902,8 @@ void JvmtiExport::post_method_exit_inner(JavaThread* thread,
|
||||
bool exception_exit,
|
||||
frame current_frame,
|
||||
jvalue& value) {
|
||||
if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_EXIT, ("[%s] Trg Method Exit triggered %s.%s",
|
||||
@ -1978,8 +1978,8 @@ void JvmtiExport::post_single_step(JavaThread *thread, Method* method, address l
|
||||
if (state == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
JvmtiEnvThreadStateIterator it(state);
|
||||
@ -2020,8 +2020,8 @@ void JvmtiExport::post_exception_throw(JavaThread *thread, Method* method, addre
|
||||
if (state == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_EXCEPTION, ("[%s] Trg Exception thrown triggered",
|
||||
@ -2142,8 +2142,8 @@ void JvmtiExport::notice_unwind_due_to_exception(JavaThread *thread, Method* met
|
||||
assert(!state->is_exception_caught(), "exception must not be caught yet.");
|
||||
state->set_exception_caught();
|
||||
|
||||
if (mh->jvmti_mount_transition() || thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (mh->jvmti_mount_transition() || thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
JvmtiEnvThreadStateIterator it(state);
|
||||
for (JvmtiEnvThreadState* ets = it.first(); ets != nullptr; ets = it.next(ets)) {
|
||||
@ -2188,8 +2188,8 @@ void JvmtiExport::post_field_access_by_jni(JavaThread *thread, oop obj,
|
||||
// function don't make the call unless there is a Java context.
|
||||
assert(thread->has_last_Java_frame(), "must be called with a Java context");
|
||||
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
ResourceMark rm;
|
||||
@ -2224,8 +2224,8 @@ void JvmtiExport::post_field_access(JavaThread *thread, Method* method,
|
||||
if (state == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_FIELD_ACCESS, ("[%s] Trg Field Access event triggered",
|
||||
@ -2274,8 +2274,8 @@ void JvmtiExport::post_field_modification_by_jni(JavaThread *thread, oop obj,
|
||||
// function don't make the call unless there is a Java context.
|
||||
assert(thread->has_last_Java_frame(), "must be called with Java context");
|
||||
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
ResourceMark rm;
|
||||
@ -2305,8 +2305,8 @@ void JvmtiExport::post_raw_field_modification(JavaThread *thread, Method* method
|
||||
address location, Klass* field_klass, Handle object, jfieldID field,
|
||||
char sig_type, jvalue *value) {
|
||||
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
if (sig_type == JVM_SIGNATURE_INT || sig_type == JVM_SIGNATURE_BOOLEAN ||
|
||||
@ -2380,8 +2380,8 @@ void JvmtiExport::post_field_modification(JavaThread *thread, Method* method,
|
||||
if (state == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_FIELD_MODIFICATION,
|
||||
@ -2419,8 +2419,8 @@ void JvmtiExport::post_native_method_bind(Method* method, address* function_ptr)
|
||||
HandleMark hm(thread);
|
||||
methodHandle mh(thread, method);
|
||||
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_NATIVE_METHOD_BIND, ("[%s] Trg Native Method Bind event triggered",
|
||||
JvmtiTrace::safe_get_thread_name(thread)));
|
||||
@ -2493,7 +2493,7 @@ void JvmtiExport::post_compiled_method_load(nmethod *nm) {
|
||||
}
|
||||
JavaThread* thread = JavaThread::current();
|
||||
|
||||
assert(!thread->is_in_any_VTMS_transition(), "compiled method load events are not allowed in any VTMS transition");
|
||||
assert(!thread->is_in_VTMS_transition(), "compiled method load events are not allowed in VTMS transition");
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
|
||||
("[%s] method compile load event triggered",
|
||||
@ -2516,7 +2516,7 @@ void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, nmethod *nm) {
|
||||
}
|
||||
JavaThread* thread = JavaThread::current();
|
||||
|
||||
assert(!thread->is_in_any_VTMS_transition(), "compiled method load events are not allowed in any VTMS transition");
|
||||
assert(!thread->is_in_VTMS_transition(), "compiled method load events are not allowed in VTMS transition");
|
||||
|
||||
EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
|
||||
("[%s] method compile load event sent %s.%s ",
|
||||
@ -2541,7 +2541,7 @@ void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const v
|
||||
|
||||
JavaThread* thread = JavaThread::current();
|
||||
|
||||
assert(!thread->is_in_any_VTMS_transition(), "dynamic code generated events are not allowed in any VTMS transition");
|
||||
assert(!thread->is_in_VTMS_transition(), "dynamic code generated events are not allowed in VTMS transition");
|
||||
|
||||
// In theory everyone coming thru here is in_vm but we need to be certain
|
||||
// because a callee will do a vm->native transition
|
||||
@ -2589,7 +2589,7 @@ void JvmtiExport::post_dynamic_code_generated(JvmtiEnv* env, const char *name,
|
||||
{
|
||||
JavaThread* thread = JavaThread::current();
|
||||
|
||||
assert(!thread->is_in_any_VTMS_transition(), "dynamic code generated events are not allowed in any VTMS transition");
|
||||
assert(!thread->is_in_VTMS_transition(), "dynamic code generated events are not allowed in VTMS transition");
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_DYNAMIC_CODE_GENERATED,
|
||||
("[%s] dynamic code generated event triggered (by GenerateEvents)",
|
||||
@ -2744,8 +2744,8 @@ void JvmtiExport::post_monitor_contended_enter(JavaThread *thread, ObjectMonitor
|
||||
if (state == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_MONITOR_CONTENDED_ENTER,
|
||||
@ -2777,8 +2777,8 @@ void JvmtiExport::post_monitor_contended_entered(JavaThread *thread, ObjectMonit
|
||||
if (state == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_MONITOR_CONTENDED_ENTERED,
|
||||
@ -2811,8 +2811,8 @@ void JvmtiExport::post_monitor_wait(JavaThread *thread, oop object,
|
||||
if (state == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_MONITOR_WAIT,
|
||||
@ -2845,8 +2845,8 @@ void JvmtiExport::post_monitor_waited(JavaThread *thread, ObjectMonitor *obj_mnt
|
||||
if (state == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_MONITOR_WAITED,
|
||||
@ -2874,8 +2874,8 @@ void JvmtiExport::post_vm_object_alloc(JavaThread *thread, oop object) {
|
||||
if (object == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
HandleMark hm(thread);
|
||||
Handle h(thread, object);
|
||||
@ -2911,8 +2911,8 @@ void JvmtiExport::post_sampled_object_alloc(JavaThread *thread, oop object) {
|
||||
if (object == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (thread->is_in_any_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in any VTMS transition
|
||||
if (thread->is_in_VTMS_transition()) {
|
||||
return; // no events should be posted if thread is in VTMS transition
|
||||
}
|
||||
|
||||
EVT_TRIG_TRACE(JVMTI_EVENT_SAMPLED_OBJECT_ALLOC,
|
||||
|
@ -353,7 +353,6 @@ JvmtiVTMSTransitionDisabler::VTMS_transition_disable_for_all() {
|
||||
{
|
||||
MonitorLocker ml(JvmtiVTMSTransition_lock);
|
||||
|
||||
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
|
||||
assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check");
|
||||
while (_SR_mode) { // Suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist.
|
||||
ml.wait(10); // Wait while there is an active suspender or resumer.
|
||||
@ -567,7 +566,6 @@ JvmtiVTMSTransitionDisabler::VTMS_vthread_start(jobject vthread) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
|
||||
assert(!thread->is_in_VTMS_transition(), "sanity check");
|
||||
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
|
||||
|
||||
// If interp_only_mode has been enabled then we must eagerly create JvmtiThreadState
|
||||
// objects for globally enabled virtual thread filtered events. Otherwise,
|
||||
@ -593,7 +591,6 @@ JvmtiVTMSTransitionDisabler::VTMS_vthread_end(jobject vthread) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
|
||||
assert(!thread->is_in_VTMS_transition(), "sanity check");
|
||||
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
|
||||
|
||||
// post VirtualThreadUnmount event before VirtualThreadEnd
|
||||
if (JvmtiExport::should_post_vthread_unmount()) {
|
||||
@ -638,7 +635,6 @@ JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount(jobject vthread, bool hide) {
|
||||
void
|
||||
JvmtiVTMSTransitionDisabler::VTMS_mount_begin(jobject vthread) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
|
||||
assert(!thread->is_in_VTMS_transition(), "sanity check");
|
||||
start_VTMS_transition(vthread, /* is_mount */ true);
|
||||
}
|
||||
@ -651,7 +647,6 @@ JvmtiVTMSTransitionDisabler::VTMS_mount_end(jobject vthread) {
|
||||
thread->rebind_to_jvmti_thread_state_of(vt);
|
||||
|
||||
assert(thread->is_in_VTMS_transition(), "sanity check");
|
||||
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
|
||||
finish_VTMS_transition(vthread, /* is_mount */ true);
|
||||
}
|
||||
|
||||
@ -659,7 +654,6 @@ void
|
||||
JvmtiVTMSTransitionDisabler::VTMS_unmount_begin(jobject vthread, bool last_unmount) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
|
||||
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
|
||||
assert(!thread->is_in_VTMS_transition(), "sanity check");
|
||||
|
||||
start_VTMS_transition(vthread, /* is_mount */ false);
|
||||
@ -672,7 +666,6 @@ void
|
||||
JvmtiVTMSTransitionDisabler::VTMS_unmount_end(jobject vthread) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
assert(thread->is_in_VTMS_transition(), "sanity check");
|
||||
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
|
||||
finish_VTMS_transition(vthread, /* is_mount */ false);
|
||||
}
|
||||
|
||||
|
@ -446,7 +446,6 @@ JavaThread::JavaThread(MemTag mem_tag) :
|
||||
#if INCLUDE_JVMTI
|
||||
_carrier_thread_suspended(false),
|
||||
_is_in_VTMS_transition(false),
|
||||
_is_in_tmp_VTMS_transition(false),
|
||||
_is_disable_suspend(false),
|
||||
_VTMS_transition_mark(false),
|
||||
#ifdef ASSERT
|
||||
|
@ -311,7 +311,6 @@ class JavaThread: public Thread {
|
||||
#if INCLUDE_JVMTI
|
||||
volatile bool _carrier_thread_suspended; // Carrier thread is externally suspended
|
||||
bool _is_in_VTMS_transition; // thread is in virtual thread mount state transition
|
||||
bool _is_in_tmp_VTMS_transition; // thread is in temporary virtual thread mount state transition
|
||||
bool _is_disable_suspend; // JVMTI suspend is temporarily disabled; used on current thread only
|
||||
bool _VTMS_transition_mark; // used for sync between VTMS transitions and disablers
|
||||
#ifdef ASSERT
|
||||
@ -675,11 +674,7 @@ private:
|
||||
}
|
||||
|
||||
bool is_in_VTMS_transition() const { return _is_in_VTMS_transition; }
|
||||
bool is_in_tmp_VTMS_transition() const { return _is_in_tmp_VTMS_transition; }
|
||||
bool is_in_any_VTMS_transition() const { return _is_in_VTMS_transition || _is_in_tmp_VTMS_transition; }
|
||||
|
||||
void set_is_in_VTMS_transition(bool val);
|
||||
void toggle_is_in_tmp_VTMS_transition() { _is_in_tmp_VTMS_transition = !_is_in_tmp_VTMS_transition; };
|
||||
|
||||
bool is_disable_suspend() const { return _is_disable_suspend; }
|
||||
void toggle_is_disable_suspend() { _is_disable_suspend = !_is_disable_suspend; };
|
||||
@ -851,7 +846,6 @@ private:
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
static ByteSize is_in_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_VTMS_transition); }
|
||||
static ByteSize is_in_tmp_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_tmp_VTMS_transition); }
|
||||
static ByteSize is_disable_suspend_offset() { return byte_offset_of(JavaThread, _is_disable_suspend); }
|
||||
#endif
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -232,8 +232,8 @@ public class ThreadLocal<T> {
|
||||
if (this instanceof TerminatingThreadLocal<?> ttl) {
|
||||
TerminatingThreadLocal.register(ttl);
|
||||
}
|
||||
if (TRACE_VTHREAD_LOCALS) {
|
||||
dumpStackIfVirtualThread();
|
||||
if (TRACE_VTHREAD_LOCALS && t == Thread.currentThread() && t.isVirtual()) {
|
||||
printStackTrace();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -249,8 +249,8 @@ public class ThreadLocal<T> {
|
||||
*/
|
||||
public void set(T value) {
|
||||
set(Thread.currentThread(), value);
|
||||
if (TRACE_VTHREAD_LOCALS) {
|
||||
dumpStackIfVirtualThread();
|
||||
if (TRACE_VTHREAD_LOCALS && Thread.currentThread().isVirtual()) {
|
||||
printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@ -799,7 +799,6 @@ public class ThreadLocal<T> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads the value of the jdk.traceVirtualThreadLocals property to determine if
|
||||
* a stack trace should be printed when a virtual thread sets a thread local.
|
||||
@ -811,30 +810,28 @@ public class ThreadLocal<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a stack trace if the current thread is a virtual thread.
|
||||
* Print the stack trace of the current thread, skipping the printStackTrace frame.
|
||||
* A thread local is used to detect reentrancy as the printing may itself use
|
||||
* thread locals.
|
||||
*/
|
||||
static void dumpStackIfVirtualThread() {
|
||||
if (Thread.currentThread() instanceof VirtualThread vthread) {
|
||||
private void printStackTrace() {
|
||||
Thread t = Thread.currentThread();
|
||||
ThreadLocalMap map = getMap(t);
|
||||
if (map.getEntry(DUMPING_STACK) == null) {
|
||||
map.set(DUMPING_STACK, true);
|
||||
try {
|
||||
var stack = StackWalkerHolder.STACK_WALKER.walk(s ->
|
||||
var stack = StackWalker.getInstance().walk(s ->
|
||||
s.skip(1) // skip caller
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
// switch to carrier thread to avoid recursive use of thread-locals
|
||||
vthread.executeOnCarrierThread(() -> {
|
||||
System.out.println(vthread);
|
||||
for (StackWalker.StackFrame frame : stack) {
|
||||
System.out.format(" %s%n", frame.toStackTraceElement());
|
||||
}
|
||||
return null;
|
||||
});
|
||||
} catch (Exception e) {
|
||||
throw new InternalError(e);
|
||||
System.out.println(t);
|
||||
for (StackWalker.StackFrame frame : stack) {
|
||||
System.out.format(" %s%n", frame.toStackTraceElement());
|
||||
}
|
||||
} finally {
|
||||
map.remove(DUMPING_STACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class StackWalkerHolder {
|
||||
static final StackWalker STACK_WALKER = StackWalker.getInstance();
|
||||
}
|
||||
private static final ThreadLocal<Boolean> DUMPING_STACK = new ThreadLocal<>();
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
@ -137,13 +136,18 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
// parking permit
|
||||
private volatile boolean parkPermit;
|
||||
|
||||
// timeout for timed-park, in nanoseconds, only accessed on current/carrier thread
|
||||
private long parkTimeout;
|
||||
|
||||
// timer task for timed-park, only accessed on current/carrier thread
|
||||
private Future<?> timeoutTask;
|
||||
|
||||
// carrier thread when mounted, accessed by VM
|
||||
private volatile Thread carrierThread;
|
||||
|
||||
// termination object when joining, created lazily if needed
|
||||
private volatile CountDownLatch termination;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the default scheduler.
|
||||
*/
|
||||
@ -246,8 +250,10 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
if (!compareAndSetState(initialState, RUNNING)) {
|
||||
return;
|
||||
}
|
||||
// consume parking permit when continuing after parking
|
||||
// consume permit when continuing after parking. If continuing after a
|
||||
// timed-park then the timeout task is cancelled.
|
||||
if (initialState == UNPARKED) {
|
||||
cancelTimeoutTask();
|
||||
setParkPermit(false);
|
||||
}
|
||||
} else {
|
||||
@ -268,6 +274,17 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel timeout task when continuing after a timed-park. The
|
||||
* timeout task may be executing, or may have already completed.
|
||||
*/
|
||||
private void cancelTimeoutTask() {
|
||||
if (timeoutTask != null) {
|
||||
timeoutTask.cancel(false);
|
||||
timeoutTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the runContinuation task to the scheduler. For the default scheduler,
|
||||
* and calling it on a worker thread, the task will be pushed to the local queue,
|
||||
@ -276,23 +293,21 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
* @param retryOnOOME true to retry indefinitely if OutOfMemoryError is thrown
|
||||
* @throws RejectedExecutionException
|
||||
*/
|
||||
@ChangesCurrentThread
|
||||
private void submitRunContinuation(Executor scheduler, boolean retryOnOOME) {
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
try {
|
||||
// The scheduler's execute method is invoked in the context of the
|
||||
// carrier thread. For the default scheduler this ensures that the
|
||||
// current thread is a ForkJoinWorkerThread so the task will be pushed
|
||||
// to the local queue. For other schedulers, it avoids deadlock that
|
||||
// would arise due to platform and virtual threads contending for a
|
||||
// lock on the scheduler's submission queue.
|
||||
if (currentThread() instanceof VirtualThread vthread) {
|
||||
vthread.switchToCarrierThread();
|
||||
// Pin the continuation to prevent the virtual thread from unmounting
|
||||
// when submitting a task. For the default scheduler this ensures that
|
||||
// the carrier doesn't change when pushing a task. For other schedulers
|
||||
// it avoids deadlock that could arise due to carriers and virtual
|
||||
// threads contending for a lock.
|
||||
if (currentThread().isVirtual()) {
|
||||
Continuation.pin();
|
||||
try {
|
||||
scheduler.execute(runContinuation);
|
||||
} finally {
|
||||
switchToVirtualThread(vthread);
|
||||
Continuation.unpin();
|
||||
}
|
||||
} else {
|
||||
scheduler.execute(runContinuation);
|
||||
@ -311,24 +326,6 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the runContinuation task to given scheduler with a lazy submit.
|
||||
* If OutOfMemoryError is thrown then the submit will be retried until it succeeds.
|
||||
* @throws RejectedExecutionException
|
||||
* @see ForkJoinPool#lazySubmit(ForkJoinTask)
|
||||
*/
|
||||
private void lazySubmitRunContinuation(ForkJoinPool pool) {
|
||||
assert Thread.currentThread() instanceof CarrierThread;
|
||||
try {
|
||||
pool.lazySubmit(ForkJoinTask.adapt(runContinuation));
|
||||
} catch (RejectedExecutionException ree) {
|
||||
submitFailed(ree);
|
||||
throw ree;
|
||||
} catch (OutOfMemoryError e) {
|
||||
submitRunContinuation(pool, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the runContinuation task to the given scheduler as an external submit.
|
||||
* If OutOfMemoryError is thrown then the submit will be retried until it succeeds.
|
||||
@ -358,6 +355,30 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
submitRunContinuation(scheduler, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy submit the runContinuation task if invoked on a carrier thread and its local
|
||||
* queue is empty. If not empty, or invoked by another thread, then this method works
|
||||
* like submitRunContinuation and just submits the task to the scheduler.
|
||||
* If OutOfMemoryError is thrown then the submit will be retried until it succeeds.
|
||||
* @throws RejectedExecutionException
|
||||
* @see ForkJoinPool#lazySubmit(ForkJoinTask)
|
||||
*/
|
||||
private void lazySubmitRunContinuation() {
|
||||
if (currentThread() instanceof CarrierThread ct && ct.getQueuedTaskCount() == 0) {
|
||||
ForkJoinPool pool = ct.getPool();
|
||||
try {
|
||||
pool.lazySubmit(ForkJoinTask.adapt(runContinuation));
|
||||
} catch (RejectedExecutionException ree) {
|
||||
submitFailed(ree);
|
||||
throw ree;
|
||||
} catch (OutOfMemoryError e) {
|
||||
submitRunContinuation();
|
||||
}
|
||||
} else {
|
||||
submitRunContinuation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the runContinuation task to the scheduler. For the default scheduler, and
|
||||
* calling it a virtual thread that uses the default scheduler, the task will be
|
||||
@ -474,45 +495,6 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
notifyJvmtiUnmount(/*hide*/false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current thread to the current carrier thread.
|
||||
*/
|
||||
@ChangesCurrentThread
|
||||
@JvmtiMountTransition
|
||||
private void switchToCarrierThread() {
|
||||
notifyJvmtiHideFrames(true);
|
||||
Thread carrier = this.carrierThread;
|
||||
assert Thread.currentThread() == this
|
||||
&& carrier == Thread.currentCarrierThread();
|
||||
carrier.setCurrentThread(carrier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current thread to the given virtual thread.
|
||||
*/
|
||||
@ChangesCurrentThread
|
||||
@JvmtiMountTransition
|
||||
private static void switchToVirtualThread(VirtualThread vthread) {
|
||||
Thread carrier = vthread.carrierThread;
|
||||
assert carrier == Thread.currentCarrierThread();
|
||||
carrier.setCurrentThread(vthread);
|
||||
notifyJvmtiHideFrames(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given value returning task on the current carrier thread.
|
||||
*/
|
||||
@ChangesCurrentThread
|
||||
<V> V executeOnCarrierThread(Callable<V> task) throws Exception {
|
||||
assert Thread.currentThread() == this;
|
||||
switchToCarrierThread();
|
||||
try {
|
||||
return task.call();
|
||||
} finally {
|
||||
switchToVirtualThread(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes Continuation.yield, notifying JVMTI (if enabled) to hide frames until
|
||||
* the continuation continues.
|
||||
@ -528,9 +510,8 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked after the continuation yields. If parking then it sets the state
|
||||
* and also re-submits the task to continue if unparked while parking.
|
||||
* If yielding due to Thread.yield then it just submits the task to continue.
|
||||
* Invoked in the context of the carrier thread after the Continuation yields when
|
||||
* parking or Thread.yield.
|
||||
*/
|
||||
private void afterYield() {
|
||||
assert carrierThread == null;
|
||||
@ -544,17 +525,20 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
|
||||
// LockSupport.park/parkNanos
|
||||
if (s == PARKING || s == TIMED_PARKING) {
|
||||
int newState = (s == PARKING) ? PARKED : TIMED_PARKED;
|
||||
setState(newState);
|
||||
int newState;
|
||||
if (s == PARKING) {
|
||||
setState(newState = PARKED);
|
||||
} else {
|
||||
// schedule unpark
|
||||
assert parkTimeout > 0;
|
||||
timeoutTask = schedule(this::unpark, parkTimeout, NANOSECONDS);
|
||||
setState(newState = TIMED_PARKED);
|
||||
}
|
||||
|
||||
// may have been unparked while parking
|
||||
if (parkPermit && compareAndSetState(newState, UNPARKED)) {
|
||||
// lazy submit to continue on the current carrier if possible
|
||||
if (currentThread() instanceof CarrierThread ct && ct.getQueuedTaskCount() == 0) {
|
||||
lazySubmitRunContinuation(ct.getPool());
|
||||
} else {
|
||||
submitRunContinuation();
|
||||
}
|
||||
// lazy submit if local queue is empty
|
||||
lazySubmitRunContinuation();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -672,7 +656,9 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
boolean yielded = false;
|
||||
setState(PARKING);
|
||||
try {
|
||||
yielded = yieldContinuation(); // may throw
|
||||
yielded = yieldContinuation();
|
||||
} catch (OutOfMemoryError e) {
|
||||
// park on carrier
|
||||
} finally {
|
||||
assert (Thread.currentThread() == this) && (yielded == (state() == RUNNING));
|
||||
if (!yielded) {
|
||||
@ -707,21 +693,23 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
if (nanos > 0) {
|
||||
long startTime = System.nanoTime();
|
||||
|
||||
// park the thread, afterYield will schedule the thread to unpark
|
||||
boolean yielded = false;
|
||||
Future<?> unparker = scheduleUnpark(nanos); // may throw OOME
|
||||
setParkTimeout(nanos);
|
||||
setState(TIMED_PARKING);
|
||||
try {
|
||||
yielded = yieldContinuation(); // may throw
|
||||
yielded = yieldContinuation();
|
||||
} catch (OutOfMemoryError e) {
|
||||
// park on carrier
|
||||
} finally {
|
||||
assert (Thread.currentThread() == this) && (yielded == (state() == RUNNING));
|
||||
if (!yielded) {
|
||||
assert state() == TIMED_PARKING;
|
||||
setState(RUNNING);
|
||||
}
|
||||
cancel(unparker);
|
||||
}
|
||||
|
||||
// park on carrier thread for remaining time when pinned
|
||||
// park on carrier thread for remaining time when pinned (or OOME)
|
||||
if (!yielded) {
|
||||
long remainingNanos = nanos - (System.nanoTime() - startTime);
|
||||
parkOnCarrierThread(true, remainingNanos);
|
||||
@ -772,38 +760,6 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule this virtual thread to be unparked after a given delay.
|
||||
*/
|
||||
@ChangesCurrentThread
|
||||
private Future<?> scheduleUnpark(long nanos) {
|
||||
assert Thread.currentThread() == this;
|
||||
// need to switch to current carrier thread to avoid nested parking
|
||||
switchToCarrierThread();
|
||||
try {
|
||||
return schedule(this::unpark, nanos, NANOSECONDS);
|
||||
} finally {
|
||||
switchToVirtualThread(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a task if it has not completed.
|
||||
*/
|
||||
@ChangesCurrentThread
|
||||
private void cancel(Future<?> future) {
|
||||
assert Thread.currentThread() == this;
|
||||
if (!future.isDone()) {
|
||||
// need to switch to current carrier thread to avoid nested parking
|
||||
switchToCarrierThread();
|
||||
try {
|
||||
future.cancel(false);
|
||||
} finally {
|
||||
switchToVirtualThread(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-enables this virtual thread for scheduling. If this virtual thread is parked
|
||||
* then its task is scheduled to continue, otherwise its next call to {@code park} or
|
||||
@ -1041,10 +997,10 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
return Thread.State.RUNNABLE;
|
||||
case PARKED:
|
||||
case PINNED:
|
||||
return State.WAITING;
|
||||
return Thread.State.WAITING;
|
||||
case TIMED_PARKED:
|
||||
case TIMED_PINNED:
|
||||
return State.TIMED_WAITING;
|
||||
return Thread.State.TIMED_WAITING;
|
||||
case TERMINATED:
|
||||
return Thread.State.TERMINATED;
|
||||
default:
|
||||
@ -1263,6 +1219,10 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
}
|
||||
}
|
||||
|
||||
private void setParkTimeout(long timeout) {
|
||||
parkTimeout = timeout;
|
||||
}
|
||||
|
||||
private void setCarrierThread(Thread carrier) {
|
||||
// U.putReferenceRelease(this, CARRIER_THREAD, carrier);
|
||||
this.carrierThread = carrier;
|
||||
@ -1286,10 +1246,6 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
@JvmtiMountTransition
|
||||
private native void notifyJvmtiUnmount(boolean hide);
|
||||
|
||||
@IntrinsicCandidate
|
||||
@JvmtiMountTransition
|
||||
private static native void notifyJvmtiHideFrames(boolean hide);
|
||||
|
||||
@IntrinsicCandidate
|
||||
private static native void notifyJvmtiDisableSuspend(boolean enter);
|
||||
|
||||
|
@ -51,6 +51,7 @@ import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import jdk.internal.access.JavaLangAccess;
|
||||
import jdk.internal.access.JavaUtilConcurrentFJPAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
@ -2632,7 +2633,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
|
||||
private void poolSubmit(boolean signalIfEmpty, ForkJoinTask<?> task) {
|
||||
Thread t; ForkJoinWorkerThread wt; WorkQueue q; boolean internal;
|
||||
if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
|
||||
if (((t = JLA.currentCarrierThread()) instanceof ForkJoinWorkerThread) &&
|
||||
(wt = (ForkJoinWorkerThread)t).pool == this) {
|
||||
internal = true;
|
||||
q = wt.workQueue;
|
||||
@ -2643,6 +2644,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
}
|
||||
q.push(task, signalIfEmpty ? this : null, internal);
|
||||
}
|
||||
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
|
||||
|
||||
/**
|
||||
* Returns queue for an external submission, bypassing call to
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -36,7 +36,6 @@ static JNINativeMethod methods[] = {
|
||||
{ "notifyJvmtiEnd", "()V", (void *)&JVM_VirtualThreadEnd },
|
||||
{ "notifyJvmtiMount", "(Z)V", (void *)&JVM_VirtualThreadMount },
|
||||
{ "notifyJvmtiUnmount", "(Z)V", (void *)&JVM_VirtualThreadUnmount },
|
||||
{ "notifyJvmtiHideFrames", "(Z)V", (void *)&JVM_VirtualThreadHideFrames },
|
||||
{ "notifyJvmtiDisableSuspend", "(Z)V", (void *)&JVM_VirtualThreadDisableSuspend },
|
||||
};
|
||||
|
||||
|
@ -30,14 +30,16 @@
|
||||
* @run main ParkWithFixedThreadPool
|
||||
*/
|
||||
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import jdk.test.lib.thread.VThreadScheduler;
|
||||
|
||||
public class ParkWithFixedThreadPool {
|
||||
public static void main(String[] args) throws Exception {
|
||||
try (ExecutorService scheduler = Executors.newFixedThreadPool(8)) {
|
||||
try (var scheduler = new Scheduler(8)) {
|
||||
int vthreadCount = 300;
|
||||
Thread[] vthreads = new Thread[vthreadCount];
|
||||
Runnable target = new Runnable() {
|
||||
@ -74,4 +76,27 @@ public class ParkWithFixedThreadPool {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Scheduler implements Executor, AutoCloseable {
|
||||
private final ExecutorService pool;
|
||||
|
||||
Scheduler(int poolSize) {
|
||||
pool = Executors.newFixedThreadPool(poolSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task) {
|
||||
try {
|
||||
pool.execute(task);
|
||||
} finally {
|
||||
// ExecutorService::execute may consume parking permit
|
||||
LockSupport.unpark(Thread.currentThread());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
pool.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user