< prev index next >

src/hotspot/share/runtime/continuation.cpp

Print this page
@@ -24,17 +24,20 @@
  
  #include "precompiled.hpp"
  #include "classfile/vmSymbols.hpp"
  #include "gc/shared/barrierSetNMethod.hpp"
  #include "oops/method.inline.hpp"
+ #include "oops/oop.inline.hpp"
+ #include "prims/jvmtiThreadState.inline.hpp"
  #include "runtime/continuation.hpp"
  #include "runtime/continuationEntry.inline.hpp"
  #include "runtime/continuationHelper.inline.hpp"
  #include "runtime/continuationJavaClasses.inline.hpp"
  #include "runtime/continuationWrapper.inline.hpp"
  #include "runtime/interfaceSupport.inline.hpp"
  #include "runtime/javaThread.inline.hpp"
+ #include "runtime/jniHandles.inline.hpp"
  #include "runtime/osThread.hpp"
  #include "runtime/vframe.inline.hpp"
  #include "runtime/vframe_hp.hpp"
  
  // defined in continuationFreezeThaw.cpp

@@ -52,10 +55,126 @@
       THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "pin underflow");
    }
  }
  JVM_END
  
+ #if INCLUDE_JVMTI
+ class JvmtiUnmountBeginMark : public StackObj {
+   JavaThread* _target;
+   int _preempt_result;
+ 
+  public:
+   JvmtiUnmountBeginMark(JavaThread* t) :
+     _target(t), _preempt_result(freeze_pinned_native) {
+     assert(!_target->is_in_any_VTMS_transition(), "must be");
+ 
+     if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
+       JvmtiVTMSTransitionDisabler::start_VTMS_transition(JNIHandles::make_local(_target->vthread()), /* is_mount */ false);
+     } else {
+       _target->set_is_in_VTMS_transition(true);
+       java_lang_Thread::set_is_in_VTMS_transition(_target->vthread(), true);
+     }
+   }
+   ~JvmtiUnmountBeginMark() {
+     assert(!_target->is_suspended(), "must be");
+ 
+     assert(_target->is_in_VTMS_transition(), "must be");
+     assert(java_lang_Thread::is_in_VTMS_transition(_target->vthread()), "must be");
+ 
+     // Read it again since for late binding agents the flag could have
+     // been set while blocked in the allocation path during freeze.
+     bool jvmti_present = JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events();
+ 
+     if (_preempt_result != freeze_ok) {
+       // Undo transition
+       if (jvmti_present) {
+         JvmtiVTMSTransitionDisabler::finish_VTMS_transition(JNIHandles::make_local(_target->vthread()), false);
+       } else {
+         _target->set_is_in_VTMS_transition(false);
+         java_lang_Thread::set_is_in_VTMS_transition(_target->vthread(), false);
+       }
+     } else {
+       if (jvmti_present) {
+         _target->rebind_to_jvmti_thread_state_of(_target->threadObj());
+         _target->set_jvmti_unmount_event_pending(true);
+       }
+     }
+   }
+   void set_preempt_result(int res) { _preempt_result = res; }
+ };
+ 
+ static bool is_safe_vthread_to_preempt_for_jvmti(JavaThread* target, oop vthread) {
+   assert(!target->has_pending_popframe(), "should be true; no support for vthreads yet");
+   JvmtiThreadState* state = target->jvmti_thread_state();
+   assert(state == nullptr || !state->is_earlyret_pending(), "should be true; no support for vthreads yet");
+ 
+   if (target->is_in_any_VTMS_transition()) {
+     // We caught target at the end of a mount transition (is_in_VTMS_transition()) or at the
+     // beginning or end of a temporary switch to carrier thread (is_in_tmp_VTMS_transition()).
+     return false;
+   }
+   return true;
+ }
+ #endif
+ 
+ static bool is_safe_vthread_to_preempt(JavaThread* target, oop vthread) {
+   if (!java_lang_VirtualThread::is_instance(vthread) ||                               // inside transition
+       java_lang_VirtualThread::state(vthread) != java_lang_VirtualThread::RUNNING) {  // inside transition
+     return false;
+   }
+   return JVMTI_ONLY(is_safe_vthread_to_preempt_for_jvmti(target, vthread)) NOT_JVMTI(true);
+ }
+ 
+ typedef int (*FreezeContFnT)(JavaThread*, intptr_t*);
+ 
+ int Continuation::try_preempt(JavaThread* target, oop continuation, bool set_state_yielding) {
+   assert(target->is_on_monitorenter(), "must be");
+   assert(target->has_last_Java_frame(), "must be");
+   assert(!target->preempting(), "must be");
+   assert(!target->is_suspended() || target->is_disable_suspend(), "must be");
+   assert(!target->has_pending_exception(), "must be");
+   assert(target->last_continuation() != nullptr, "must be");
+   assert(target->last_continuation()->cont_oop(target) == continuation, "must be");
+   assert(!is_continuation_preempted(continuation), "shouldn't be");
+   assert(Continuation::continuation_scope(continuation) == java_lang_VirtualThread::vthread_scope(), "must be");
+ 
+   if (!VM_Version::supports_cont_preemption()) {
+     return unsupported;
+   }
+ 
+   if (is_continuation_done(continuation)) {
+     return freeze_not_mounted;
+   }
+ 
+   // Continuation is mounted and it's not done so check if it's safe to preempt.
+   if (!is_safe_vthread_to_preempt(target, target->vthread())) {
+     return freeze_pinned_native;
+   }
+ 
+ #if INCLUDE_JVMTI
+   JvmtiUnmountBeginMark jubm(target);
+ #endif
+   target->set_preempting(true);
+   int res = CAST_TO_FN_PTR(FreezeContFnT, freeze_preempt_entry())(target, target->last_Java_sp());
+   log_trace(continuations, preempt)("try_preempt: %d", res);
+   JVMTI_ONLY(jubm.set_preempt_result(res);)
+   if (res != freeze_ok) {
+     target->set_preempting(false);
+   } else if (set_state_yielding) {
+     java_lang_VirtualThread::set_state(target->vthread(), java_lang_VirtualThread::YIELDING);
+   }
+   return res;
+ }
+ 
+ bool Continuation::is_continuation_preempted(oop cont) {
+   return jdk_internal_vm_Continuation::is_preempted(cont);
+ }
+ 
+ bool Continuation::is_continuation_done(oop cont) {
+   return jdk_internal_vm_Continuation::done(cont);
+ }
+ 
  #ifndef PRODUCT
  static jlong java_tid(JavaThread* thread) {
    return java_lang_Thread::thread_id(thread->threadObj());
  }
  #endif
< prev index next >