< prev index next > src/hotspot/share/services/threadService.cpp
Print this page
int _frame_count; // length of _methods and _bcis arrays
GrowableArray<Method*>* _methods;
GrowableArray<int>* _bcis;
JavaThreadStatus _thread_status;
OopHandle _thread_name;
GrowableArray<OwnedLock>* _locks;
Blocker _blocker;
GetThreadSnapshotHandshakeClosure(Handle thread_h, JavaThread* java_thread):
HandshakeClosure("GetThreadSnapshotHandshakeClosure"),
_thread_h(thread_h), _java_thread(java_thread),
_frame_count(0), _methods(nullptr), _bcis(nullptr),
! _thread_status(), _thread_name(nullptr),
! _locks(nullptr), _blocker() {
}
virtual ~GetThreadSnapshotHandshakeClosure() {
delete _methods;
delete _bcis;
_thread_name.release(oop_storage());
if (_locks != nullptr) {
for (int i = 0; i < _locks->length(); i++) {
_locks->at(i)._obj.release(oop_storage());
}
delete _locks;
int _frame_count; // length of _methods and _bcis arrays
GrowableArray<Method*>* _methods;
GrowableArray<int>* _bcis;
JavaThreadStatus _thread_status;
OopHandle _thread_name;
+ OopHandle _carrier_thread;
GrowableArray<OwnedLock>* _locks;
Blocker _blocker;
+ bool _completed;
GetThreadSnapshotHandshakeClosure(Handle thread_h, JavaThread* java_thread):
HandshakeClosure("GetThreadSnapshotHandshakeClosure"),
_thread_h(thread_h), _java_thread(java_thread),
_frame_count(0), _methods(nullptr), _bcis(nullptr),
! _thread_status(), _thread_name(nullptr), _carrier_thread(nullptr),
! _locks(nullptr), _blocker(),
+ _completed(false) {
}
virtual ~GetThreadSnapshotHandshakeClosure() {
delete _methods;
delete _bcis;
_thread_name.release(oop_storage());
+ _carrier_thread.release(oop_storage());
if (_locks != nullptr) {
for (int i = 0; i < _locks->length(); i++) {
_locks->at(i)._obj.release(oop_storage());
}
delete _locks;
public:
void do_thread(Thread* th) override {
Thread* current = Thread::current();
bool is_virtual = java_lang_VirtualThread::is_instance(_thread_h());
! if (_java_thread != nullptr) {
! if (is_virtual) {
! // mounted vthread, use carrier thread state
! oop carrier_thread = java_lang_VirtualThread::carrier_thread(_thread_h());
! assert(carrier_thread != nullptr, "should only get here for a mounted vthread");
! _thread_status = java_lang_Thread::get_thread_status(carrier_thread);
} else {
! _thread_status = java_lang_Thread::get_thread_status(_thread_h());
}
} else {
! // unmounted vthread
- int vt_state = java_lang_VirtualThread::state(_thread_h());
- _thread_status = java_lang_VirtualThread::map_state_to_thread_status(vt_state);
}
_thread_name = OopHandle(oop_storage(), java_lang_Thread::name(_thread_h()));
if (_java_thread != nullptr && !_java_thread->has_last_Java_frame()) {
// stack trace is empty
return;
public:
void do_thread(Thread* th) override {
Thread* current = Thread::current();
bool is_virtual = java_lang_VirtualThread::is_instance(_thread_h());
!
! // For a mounted virtual thread then we must check that we are in a handshake with
! // the JavaThread that has the virtual thread's continuation mounted.
! if (is_virtual && _java_thread != nullptr) {
! const ContinuationEntry* ce = _java_thread->vthread_continuation();
! if (ce == nullptr || ce->cont_oop(_java_thread) != java_lang_VirtualThread::continuation(_thread_h())) {
+ return; // continuation not mounted
+ }
+ assert(_java_thread->vthread() == _thread_h(), "Wrong Thread identity");
+ }
+
+ // thread status, and carrier if mounted
+ if (is_virtual) {
+ if (_java_thread != nullptr) {
+ // use carrier status when mounted
+ _thread_status = java_lang_Thread::get_thread_status(_java_thread->threadObj());
+ _carrier_thread = OopHandle(oop_storage(), _java_thread->threadObj());
} else {
! // use virtual thread state when unmounted
+ int vt_state = java_lang_VirtualThread::state(_thread_h());
+ assert((vt_state & java_lang_VirtualThread::SUSPENDED) != 0, "Unmounted virtual thread should be suspended");
+ _thread_status = java_lang_VirtualThread::map_state_to_thread_status(vt_state);
}
} else {
! _thread_status = java_lang_Thread::get_thread_status(_thread_h());
}
+
_thread_name = OopHandle(oop_storage(), java_lang_Thread::name(_thread_h()));
if (_java_thread != nullptr && !_java_thread->has_last_Java_frame()) {
// stack trace is empty
return;
_bcis->push(vfst.bci());
total_count++;
}
_frame_count = total_count;
+
+ _completed = true;
+ }
+
+ bool is_completed() {
+ return _completed;
}
};
class jdk_internal_vm_ThreadLock: AllStatic {
static bool _inited;
int jdk_internal_vm_ThreadSnapshot::_stackTrace_offset;
int jdk_internal_vm_ThreadSnapshot::_locks_offset;
int jdk_internal_vm_ThreadSnapshot::_blockerTypeOrdinal_offset;
int jdk_internal_vm_ThreadSnapshot::_blockerObject_offset;
! oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) {
ThreadsListHandle tlh(THREAD);
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
int jdk_internal_vm_ThreadSnapshot::_stackTrace_offset;
int jdk_internal_vm_ThreadSnapshot::_locks_offset;
int jdk_internal_vm_ThreadSnapshot::_blockerTypeOrdinal_offset;
int jdk_internal_vm_ThreadSnapshot::_blockerObject_offset;
! oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, jboolean suspended_by_caller, TRAPS) {
ThreadsListHandle tlh(THREAD);
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
oop thread_oop;
bool has_javathread = tlh.cv_internal_thread_to_JavaThread(jthread, &java_thread, &thread_oop);
assert((has_javathread && thread_oop != nullptr) || !has_javathread, "Missing Thread oop");
Handle thread_h(THREAD, thread_oop);
bool is_virtual = java_lang_VirtualThread::is_instance(thread_h()); // Deals with null
-
if (!has_javathread && !is_virtual) {
return nullptr; // thread terminated so not of interest
}
! // wrapper to auto delete JvmtiVTMSTransitionDisabler
! class TransitionDisabler {
! JvmtiVTMSTransitionDisabler* _transition_disabler;
! public:
! TransitionDisabler(): _transition_disabler(nullptr) {}
! ~TransitionDisabler() {
- reset();
- }
- void init(jobject jthread) {
- _transition_disabler = new (mtInternal) JvmtiVTMSTransitionDisabler(jthread);
- }
- void reset() {
- if (_transition_disabler != nullptr) {
- delete _transition_disabler;
- _transition_disabler = nullptr;
- }
- }
- } transition_disabler;
-
- Handle carrier_thread;
- if (is_virtual) {
- // 1st need to disable mount/unmount transitions
- transition_disabler.init(jthread);
-
- carrier_thread = Handle(THREAD, java_lang_VirtualThread::carrier_thread(thread_h()));
- if (carrier_thread != nullptr) {
- // Note: The java_thread associated with this carrier_thread may not be
- // protected by the ThreadsListHandle above. There could have been an
- // unmount and remount after the ThreadsListHandle above was created
- // and before the JvmtiVTMSTransitionDisabler was created. However, as
- // we have disabled transitions, if we are mounted on it, then it cannot
- // terminate and so is safe to handshake with.
- java_thread = java_lang_Thread::thread(carrier_thread());
- } else {
- // We may have previously found a carrier but the virtual thread has unmounted
- // after that, so clear that previous reference.
- java_thread = nullptr;
- }
- } else {
- java_thread = java_lang_Thread::thread(thread_h());
}
// Handshake with target
GetThreadSnapshotHandshakeClosure cl(thread_h, java_thread);
if (java_thread == nullptr) {
// unmounted vthread, execute on the current thread
cl.do_thread(nullptr);
} else {
Handshake::execute(&cl, &tlh, java_thread);
}
!
! // all info is collected, can enable transitions.
! transition_disabler.reset();
// StackTrace
InstanceKlass* ste_klass = vmClasses::StackTraceElement_klass();
assert(ste_klass != nullptr, "must be loaded");
oop thread_oop;
bool has_javathread = tlh.cv_internal_thread_to_JavaThread(jthread, &java_thread, &thread_oop);
assert((has_javathread && thread_oop != nullptr) || !has_javathread, "Missing Thread oop");
Handle thread_h(THREAD, thread_oop);
bool is_virtual = java_lang_VirtualThread::is_instance(thread_h()); // Deals with null
if (!has_javathread && !is_virtual) {
return nullptr; // thread terminated so not of interest
}
! // unmounted virtual thread needs to be suspended by caller
! if (is_virtual && !has_javathread) {
! if (suspended_by_caller == JNI_FALSE) {
! return nullptr; // called needs to suspend and retry
! }
! assert((java_lang_VirtualThread::state(thread_h()) & java_lang_VirtualThread::SUSPENDED) != 0, "Not suspended");
}
// Handshake with target
GetThreadSnapshotHandshakeClosure cl(thread_h, java_thread);
if (java_thread == nullptr) {
// unmounted vthread, execute on the current thread
cl.do_thread(nullptr);
} else {
Handshake::execute(&cl, &tlh, java_thread);
}
! if (!cl.is_completed()) {
! return nullptr;
! }
// StackTrace
InstanceKlass* ste_klass = vmClasses::StackTraceElement_klass();
assert(ste_klass != nullptr, "must be loaded");
}
Handle snapshot = jdk_internal_vm_ThreadSnapshot::allocate(InstanceKlass::cast(snapshot_klass), CHECK_NULL);
jdk_internal_vm_ThreadSnapshot::set_name(snapshot(), cl._thread_name.resolve());
jdk_internal_vm_ThreadSnapshot::set_thread_status(snapshot(), (int)cl._thread_status);
! jdk_internal_vm_ThreadSnapshot::set_carrier_thread(snapshot(), carrier_thread());
jdk_internal_vm_ThreadSnapshot::set_stack_trace(snapshot(), trace());
jdk_internal_vm_ThreadSnapshot::set_locks(snapshot(), locks());
if (!cl._blocker.is_empty()) {
jdk_internal_vm_ThreadSnapshot::set_blocker(snapshot(), cl._blocker._type, cl._blocker._obj.resolve());
}
}
Handle snapshot = jdk_internal_vm_ThreadSnapshot::allocate(InstanceKlass::cast(snapshot_klass), CHECK_NULL);
jdk_internal_vm_ThreadSnapshot::set_name(snapshot(), cl._thread_name.resolve());
jdk_internal_vm_ThreadSnapshot::set_thread_status(snapshot(), (int)cl._thread_status);
! jdk_internal_vm_ThreadSnapshot::set_carrier_thread(snapshot(), cl._carrier_thread.resolve());
jdk_internal_vm_ThreadSnapshot::set_stack_trace(snapshot(), trace());
jdk_internal_vm_ThreadSnapshot::set_locks(snapshot(), locks());
if (!cl._blocker.is_empty()) {
jdk_internal_vm_ThreadSnapshot::set_blocker(snapshot(), cl._blocker._type, cl._blocker._obj.resolve());
}
< prev index next >