8242428: JVMTI thread operations should use Thread-Local Handshake
Reviewed-by: dcubed, sspitsyn, dholmes
This commit is contained in:
parent
09510a15a1
commit
faf4d7ccb7
@ -1535,15 +1535,14 @@ JvmtiEnv::GetStackTrace(JavaThread* java_thread, jint start_depth, jint max_fram
|
||||
jvmtiError err = JVMTI_ERROR_NONE;
|
||||
|
||||
// It is only safe to perform the direct operation on the current
|
||||
// thread. All other usage needs to use a vm-safepoint-op for safety.
|
||||
// thread. All other usage needs to use a direct handshake for safety.
|
||||
if (java_thread == JavaThread::current()) {
|
||||
err = get_stack_trace(java_thread, start_depth, max_frame_count, frame_buffer, count_ptr);
|
||||
} else {
|
||||
// JVMTI get stack trace at safepoint. Do not require target thread to
|
||||
// be suspended.
|
||||
VM_GetStackTrace op(this, java_thread, start_depth, max_frame_count, frame_buffer, count_ptr);
|
||||
VMThread::execute(&op);
|
||||
err = op.result();
|
||||
// Get stack trace with handshake.
|
||||
GetStackTraceClosure op(this, start_depth, max_frame_count, frame_buffer, count_ptr);
|
||||
bool executed = Handshake::execute_direct(&op, java_thread);
|
||||
err = executed ? op.result() : JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
}
|
||||
|
||||
return err;
|
||||
@ -1575,12 +1574,31 @@ JvmtiEnv::GetAllStackTraces(jint max_frame_count, jvmtiStackInfo** stack_info_pt
|
||||
jvmtiError
|
||||
JvmtiEnv::GetThreadListStackTraces(jint thread_count, const jthread* thread_list, jint max_frame_count, jvmtiStackInfo** stack_info_ptr) {
|
||||
jvmtiError err = JVMTI_ERROR_NONE;
|
||||
// JVMTI get stack traces at safepoint.
|
||||
VM_GetThreadListStackTraces op(this, thread_count, thread_list, max_frame_count);
|
||||
VMThread::execute(&op);
|
||||
err = op.result();
|
||||
if (err == JVMTI_ERROR_NONE) {
|
||||
*stack_info_ptr = op.stack_info();
|
||||
|
||||
if (thread_count == 1) {
|
||||
// Use direct handshake if we need to get only one stack trace.
|
||||
JavaThread *current_thread = JavaThread::current();
|
||||
ThreadsListHandle tlh(current_thread);
|
||||
JavaThread *java_thread;
|
||||
err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), *thread_list, &java_thread, NULL);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
return err;
|
||||
}
|
||||
|
||||
GetSingleStackTraceClosure op(this, current_thread, *thread_list, max_frame_count);
|
||||
bool executed = Handshake::execute_direct(&op, java_thread);
|
||||
err = executed ? op.result() : JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
if (err == JVMTI_ERROR_NONE) {
|
||||
*stack_info_ptr = op.stack_info();
|
||||
}
|
||||
} else {
|
||||
// JVMTI get stack traces at safepoint.
|
||||
VM_GetThreadListStackTraces op(this, thread_count, thread_list, max_frame_count);
|
||||
VMThread::execute(&op);
|
||||
err = op.result();
|
||||
if (err == JVMTI_ERROR_NONE) {
|
||||
*stack_info_ptr = op.stack_info();
|
||||
}
|
||||
}
|
||||
return err;
|
||||
} /* end GetThreadListStackTraces */
|
||||
|
@ -816,13 +816,14 @@ JvmtiEnvBase::get_stack_trace(JavaThread *java_thread,
|
||||
#ifdef ASSERT
|
||||
uint32_t debug_bits = 0;
|
||||
#endif
|
||||
assert((SafepointSynchronize::is_at_safepoint() ||
|
||||
java_thread->is_thread_fully_suspended(false, &debug_bits)),
|
||||
"at safepoint or target thread is suspended");
|
||||
Thread *current_thread = Thread::current();
|
||||
assert(current_thread == java_thread ||
|
||||
SafepointSynchronize::is_at_safepoint() ||
|
||||
current_thread == java_thread->active_handshaker(),
|
||||
"call by myself / at safepoint / at handshake");
|
||||
int count = 0;
|
||||
if (java_thread->has_last_Java_frame()) {
|
||||
RegisterMap reg_map(java_thread);
|
||||
Thread* current_thread = Thread::current();
|
||||
ResourceMark rm(current_thread);
|
||||
javaVFrame *jvf = java_thread->last_java_vframe(®_map);
|
||||
HandleMark hm(current_thread);
|
||||
@ -1154,8 +1155,14 @@ struct StackInfoNode {
|
||||
// Note that either or both of thr and thread_oop
|
||||
// may be null if the thread is new or has exited.
|
||||
void
|
||||
VM_GetMultipleStackTraces::fill_frames(jthread jt, JavaThread *thr, oop thread_oop) {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
||||
MultipleStackTracesCollector::fill_frames(jthread jt, JavaThread *thr, oop thread_oop) {
|
||||
#ifdef ASSERT
|
||||
Thread *current_thread = Thread::current();
|
||||
assert(current_thread == thr ||
|
||||
SafepointSynchronize::is_at_safepoint() ||
|
||||
current_thread == thr->active_handshaker(),
|
||||
"call by myself / at safepoint / at handshake");
|
||||
#endif
|
||||
|
||||
jint state = 0;
|
||||
struct StackInfoNode *node = NEW_RESOURCE_OBJ(struct StackInfoNode);
|
||||
@ -1199,7 +1206,7 @@ VM_GetMultipleStackTraces::fill_frames(jthread jt, JavaThread *thr, oop thread_o
|
||||
// Based on the stack information in the linked list, allocate memory
|
||||
// block to return and fill it from the info in the linked list.
|
||||
void
|
||||
VM_GetMultipleStackTraces::allocate_and_fill_stacks(jint thread_count) {
|
||||
MultipleStackTracesCollector::allocate_and_fill_stacks(jint thread_count) {
|
||||
// do I need to worry about alignment issues?
|
||||
jlong alloc_size = thread_count * sizeof(jvmtiStackInfo)
|
||||
+ _frame_count_total * sizeof(jvmtiFrameInfo);
|
||||
@ -1248,14 +1255,27 @@ VM_GetThreadListStackTraces::doit() {
|
||||
// only return an error from here if we didn't get a valid
|
||||
// thread_oop.
|
||||
if (thread_oop == NULL) {
|
||||
set_result(err);
|
||||
_collector.set_result(err);
|
||||
return;
|
||||
}
|
||||
// We have a valid thread_oop.
|
||||
}
|
||||
fill_frames(jt, java_thread, thread_oop);
|
||||
_collector.fill_frames(jt, java_thread, thread_oop);
|
||||
}
|
||||
_collector.allocate_and_fill_stacks(_thread_count);
|
||||
}
|
||||
|
||||
void
|
||||
GetSingleStackTraceClosure::do_thread(Thread *target) {
|
||||
assert(target->is_Java_thread(), "just checking");
|
||||
JavaThread *jt = (JavaThread *)target;
|
||||
oop thread_oop = jt->threadObj();
|
||||
|
||||
if (!jt->is_exiting() && thread_oop != NULL) {
|
||||
ResourceMark rm;
|
||||
_collector.fill_frames(_jthread, jt, thread_oop);
|
||||
_collector.allocate_and_fill_stacks(1);
|
||||
}
|
||||
allocate_and_fill_stacks(_thread_count);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1272,11 +1292,11 @@ VM_GetAllStackTraces::doit() {
|
||||
!jt->is_hidden_from_external_view()) {
|
||||
++_final_thread_count;
|
||||
// Handle block of the calling thread is used to create local refs.
|
||||
fill_frames((jthread)JNIHandles::make_local(_calling_thread, thread_oop),
|
||||
jt, thread_oop);
|
||||
_collector.fill_frames((jthread)JNIHandles::make_local(_calling_thread, thread_oop),
|
||||
jt, thread_oop);
|
||||
}
|
||||
}
|
||||
allocate_and_fill_stacks(_final_thread_count);
|
||||
_collector.allocate_and_fill_stacks(_final_thread_count);
|
||||
}
|
||||
|
||||
// Verifies that the top frame is a java frame in an expected state.
|
||||
@ -1528,12 +1548,11 @@ GetCurrentContendedMonitorClosure::do_thread(Thread *target) {
|
||||
}
|
||||
|
||||
void
|
||||
VM_GetStackTrace::doit() {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||
ThreadsListHandle tlh;
|
||||
if (_java_thread != NULL && tlh.includes(_java_thread)
|
||||
&& !_java_thread->is_exiting() && _java_thread->threadObj() != NULL) {
|
||||
_result = ((JvmtiEnvBase *)_env)->get_stack_trace(_java_thread,
|
||||
GetStackTraceClosure::do_thread(Thread *target) {
|
||||
assert(target->is_Java_thread(), "just checking");
|
||||
JavaThread *jt = (JavaThread *)target;
|
||||
if (!jt->is_exiting() && jt->threadObj() != NULL) {
|
||||
_result = ((JvmtiEnvBase *)_env)->get_stack_trace(jt,
|
||||
_start_depth, _max_count,
|
||||
_frame_buffer, _count_ptr);
|
||||
}
|
||||
|
@ -437,11 +437,10 @@ public:
|
||||
void do_thread(Thread *target);
|
||||
};
|
||||
|
||||
// VM operation to get stack trace at safepoint.
|
||||
class VM_GetStackTrace : public VM_Operation {
|
||||
// HandshakeClosure to get stack trace.
|
||||
class GetStackTraceClosure : public HandshakeClosure {
|
||||
private:
|
||||
JvmtiEnv *_env;
|
||||
JavaThread *_java_thread;
|
||||
jint _start_depth;
|
||||
jint _max_count;
|
||||
jvmtiFrameInfo *_frame_buffer;
|
||||
@ -449,26 +448,25 @@ private:
|
||||
jvmtiError _result;
|
||||
|
||||
public:
|
||||
VM_GetStackTrace(JvmtiEnv *env, JavaThread *java_thread,
|
||||
jint start_depth, jint max_count,
|
||||
jvmtiFrameInfo* frame_buffer, jint* count_ptr) {
|
||||
_env = env;
|
||||
_java_thread = java_thread;
|
||||
_start_depth = start_depth;
|
||||
_max_count = max_count;
|
||||
_frame_buffer = frame_buffer;
|
||||
_count_ptr = count_ptr;
|
||||
GetStackTraceClosure(JvmtiEnv *env, jint start_depth, jint max_count,
|
||||
jvmtiFrameInfo* frame_buffer, jint* count_ptr)
|
||||
: HandshakeClosure("GetStackTrace"),
|
||||
_env(env),
|
||||
_start_depth(start_depth),
|
||||
_max_count(max_count),
|
||||
_frame_buffer(frame_buffer),
|
||||
_count_ptr(count_ptr),
|
||||
_result(JVMTI_ERROR_THREAD_NOT_ALIVE) {
|
||||
}
|
||||
jvmtiError result() { return _result; }
|
||||
VMOp_Type type() const { return VMOp_GetStackTrace; }
|
||||
void doit();
|
||||
void do_thread(Thread *target);
|
||||
};
|
||||
|
||||
// forward declaration
|
||||
struct StackInfoNode;
|
||||
|
||||
// VM operation to get stack trace at safepoint.
|
||||
class VM_GetMultipleStackTraces : public VM_Operation {
|
||||
// Get stack trace at safepoint or at direct handshake.
|
||||
class MultipleStackTracesCollector {
|
||||
private:
|
||||
JvmtiEnv *_env;
|
||||
jint _max_frame_count;
|
||||
@ -482,58 +480,82 @@ private:
|
||||
struct StackInfoNode *head() { return _head; }
|
||||
void set_head(StackInfoNode *head) { _head = head; }
|
||||
|
||||
protected:
|
||||
public:
|
||||
MultipleStackTracesCollector(JvmtiEnv *env, jint max_frame_count)
|
||||
: _env(env),
|
||||
_max_frame_count(max_frame_count),
|
||||
_stack_info(NULL),
|
||||
_result(JVMTI_ERROR_NONE),
|
||||
_frame_count_total(0),
|
||||
_head(NULL) {
|
||||
}
|
||||
void set_result(jvmtiError result) { _result = result; }
|
||||
void fill_frames(jthread jt, JavaThread *thr, oop thread_oop);
|
||||
void allocate_and_fill_stacks(jint thread_count);
|
||||
|
||||
public:
|
||||
VM_GetMultipleStackTraces(JvmtiEnv *env, jint max_frame_count) {
|
||||
_env = env;
|
||||
_max_frame_count = max_frame_count;
|
||||
_frame_count_total = 0;
|
||||
_head = NULL;
|
||||
_result = JVMTI_ERROR_NONE;
|
||||
}
|
||||
VMOp_Type type() const { return VMOp_GetMultipleStackTraces; }
|
||||
jvmtiStackInfo *stack_info() { return _stack_info; }
|
||||
jvmtiError result() { return _result; }
|
||||
};
|
||||
|
||||
|
||||
// VM operation to get stack trace at safepoint.
|
||||
class VM_GetAllStackTraces : public VM_GetMultipleStackTraces {
|
||||
class VM_GetAllStackTraces : public VM_Operation {
|
||||
private:
|
||||
JavaThread *_calling_thread;
|
||||
jint _final_thread_count;
|
||||
MultipleStackTracesCollector _collector;
|
||||
|
||||
public:
|
||||
VM_GetAllStackTraces(JvmtiEnv *env, JavaThread *calling_thread,
|
||||
jint max_frame_count)
|
||||
: VM_GetMultipleStackTraces(env, max_frame_count) {
|
||||
_calling_thread = calling_thread;
|
||||
: _calling_thread(calling_thread),
|
||||
_final_thread_count(0),
|
||||
_collector(env, max_frame_count) {
|
||||
}
|
||||
VMOp_Type type() const { return VMOp_GetAllStackTraces; }
|
||||
void doit();
|
||||
jint final_thread_count() { return _final_thread_count; }
|
||||
jvmtiStackInfo *stack_info() { return _collector.stack_info(); }
|
||||
jvmtiError result() { return _collector.result(); }
|
||||
};
|
||||
|
||||
// VM operation to get stack trace at safepoint.
|
||||
class VM_GetThreadListStackTraces : public VM_GetMultipleStackTraces {
|
||||
class VM_GetThreadListStackTraces : public VM_Operation {
|
||||
private:
|
||||
jint _thread_count;
|
||||
const jthread* _thread_list;
|
||||
MultipleStackTracesCollector _collector;
|
||||
|
||||
public:
|
||||
VM_GetThreadListStackTraces(JvmtiEnv *env, jint thread_count, const jthread* thread_list, jint max_frame_count)
|
||||
: VM_GetMultipleStackTraces(env, max_frame_count) {
|
||||
_thread_count = thread_count;
|
||||
_thread_list = thread_list;
|
||||
: _thread_count(thread_count),
|
||||
_thread_list(thread_list),
|
||||
_collector(env, max_frame_count) {
|
||||
}
|
||||
VMOp_Type type() const { return VMOp_GetThreadListStackTraces; }
|
||||
void doit();
|
||||
jvmtiStackInfo *stack_info() { return _collector.stack_info(); }
|
||||
jvmtiError result() { return _collector.result(); }
|
||||
};
|
||||
|
||||
// HandshakeClosure to get single stack trace.
|
||||
class GetSingleStackTraceClosure : public HandshakeClosure {
|
||||
private:
|
||||
JavaThread *_calling_thread;
|
||||
jthread _jthread;
|
||||
MultipleStackTracesCollector _collector;
|
||||
|
||||
public:
|
||||
GetSingleStackTraceClosure(JvmtiEnv *env, JavaThread *calling_thread,
|
||||
jthread thread, jint max_frame_count)
|
||||
: HandshakeClosure("GetSingleStackTrace"),
|
||||
_calling_thread(calling_thread),
|
||||
_jthread(thread),
|
||||
_collector(env, max_frame_count) {
|
||||
}
|
||||
void do_thread(Thread *target);
|
||||
jvmtiStackInfo *stack_info() { return _collector.stack_info(); }
|
||||
jvmtiError result() { return _collector.result(); }
|
||||
};
|
||||
|
||||
// VM operation to count stack frames at safepoint.
|
||||
class VM_GetFrameCount : public VM_Operation {
|
||||
|
@ -79,8 +79,6 @@
|
||||
template(UpdateForPopTopFrame) \
|
||||
template(SetFramePop) \
|
||||
template(GetObjectMonitorUsage) \
|
||||
template(GetStackTrace) \
|
||||
template(GetMultipleStackTraces) \
|
||||
template(GetAllStackTraces) \
|
||||
template(GetThreadListStackTraces) \
|
||||
template(GetFrameCount) \
|
||||
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, NTT DATA.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8242428
|
||||
* @summary Verifies JVMTI GetThreadListStackTraces API with thread_count = 1
|
||||
* @library /test/lib
|
||||
* @run main/othervm/native -agentlib:OneGetThreadListStackTraces OneGetThreadListStackTraces
|
||||
*
|
||||
*/
|
||||
|
||||
public class OneGetThreadListStackTraces {
|
||||
|
||||
private static native void checkCallStacks(Thread thread);
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
/* Check call stack native */
|
||||
checkCallStacks(Thread.currentThread());
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, NTT DATA.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include <jvmti.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_FRAMES 100
|
||||
#define ERR_MSG_LEN 1024
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static jvmtiEnv *jvmti = NULL;
|
||||
|
||||
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
|
||||
return jvm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_11);
|
||||
}
|
||||
|
||||
static void check_frame_info(JNIEnv *env, jvmtiFrameInfo *fi1, jvmtiFrameInfo *fi2) {
|
||||
char err_msg[ERR_MSG_LEN] = {0};
|
||||
if (fi1->method != fi2->method) { /* jvmtiFrameInfo::method */
|
||||
snprintf(err_msg, sizeof(err_msg),
|
||||
"method is different: fi1 = %" PRIxPTR ", fi2 = %" PRIxPTR,
|
||||
(uintptr_t)fi1->method, (uintptr_t)fi2->method);
|
||||
env->FatalError(err_msg);
|
||||
} else if (fi1->location != fi2->location) { /* jvmtiFrameInfo::location */
|
||||
snprintf(err_msg, sizeof(err_msg),
|
||||
"location is different: fi1 = %" PRId64 ", fi2 = %" PRId64,
|
||||
(int64_t)fi1->location, (int64_t)fi2->location);
|
||||
env->FatalError(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_stack_info(JNIEnv *env, jvmtiStackInfo *si1, jvmtiStackInfo *si2) {
|
||||
char err_msg[ERR_MSG_LEN] = {0};
|
||||
|
||||
jboolean is_same = env->IsSameObject(si1->thread, si2->thread);
|
||||
if (env->ExceptionOccurred()) {
|
||||
env->ExceptionDescribe();
|
||||
env->FatalError(__FILE__);
|
||||
}
|
||||
|
||||
if (!is_same) { /* jvmtiStackInfo::thread */
|
||||
snprintf(err_msg, sizeof(err_msg),
|
||||
"thread is different: si1 = %" PRIxPTR ", si2 = %" PRIxPTR,
|
||||
(uintptr_t)si1->thread, (uintptr_t)si2->thread);
|
||||
env->FatalError(err_msg);
|
||||
} else if (si1->state != si2->state) { /* jvmtiStackInfo::state */
|
||||
snprintf(err_msg, sizeof(err_msg),
|
||||
"state is different: si1 = %d, si2 = %d", si1->state, si2->state);
|
||||
env->FatalError(err_msg);
|
||||
} else if (si1->frame_count != si2->frame_count) { /* jvmtiStackInfo::frame_count */
|
||||
snprintf(err_msg, sizeof(err_msg),
|
||||
"frame_count is different: si1 = %d, si2 = %d",
|
||||
si1->frame_count, si2->frame_count);
|
||||
env->FatalError(err_msg);
|
||||
} else {
|
||||
/* Iterate all jvmtiFrameInfo to check */
|
||||
for (int i = 0; i < si1->frame_count; i++) {
|
||||
check_frame_info(env, &si1->frame_buffer[i], &si2->frame_buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_OneGetThreadListStackTraces_checkCallStacks(JNIEnv *env, jclass cls, jthread thread) {
|
||||
jvmtiStackInfo *stack_info, *target_info, *target_one_info;
|
||||
jvmtiError result;
|
||||
char err_msg[ERR_MSG_LEN] = {0};
|
||||
|
||||
/* Get all stack traces */
|
||||
jint num_threads;
|
||||
result = jvmti->GetAllStackTraces(MAX_FRAMES, &stack_info, &num_threads);
|
||||
if (result != JVMTI_ERROR_NONE) {
|
||||
snprintf(err_msg, sizeof(err_msg),
|
||||
"GetAllStackTraces(): result = %d", result);
|
||||
env->FatalError(err_msg);
|
||||
}
|
||||
|
||||
/* Find jvmtiStackInfo for `thread` (in arguments) */
|
||||
jboolean is_same;
|
||||
target_info = NULL;
|
||||
for (jint i = 0; i < num_threads; i++) {
|
||||
is_same = env->IsSameObject(stack_info[i].thread, thread);
|
||||
if (env->ExceptionOccurred()) {
|
||||
env->ExceptionDescribe();
|
||||
env->FatalError(__FILE__);
|
||||
}
|
||||
if (is_same) {
|
||||
target_info = &stack_info[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target_info == NULL) {
|
||||
env->FatalError("Target thread not found");
|
||||
}
|
||||
|
||||
/*
|
||||
* Get jvmtiStackInfo via GetThreadListStackTraces().
|
||||
* It expects to perform in Thread Local Handshake because thread count is 1.
|
||||
*/
|
||||
result = jvmti->GetThreadListStackTraces(1, &thread,
|
||||
MAX_FRAMES, &target_one_info);
|
||||
if (result != JVMTI_ERROR_NONE) {
|
||||
snprintf(err_msg, sizeof(err_msg),
|
||||
"GetThreadListStackTraces(): result = %d", result);
|
||||
env->FatalError(err_msg);
|
||||
}
|
||||
|
||||
check_stack_info(env, target_info, target_one_info);
|
||||
|
||||
jvmti->Deallocate(reinterpret_cast<unsigned char *>(stack_info));
|
||||
jvmti->Deallocate(reinterpret_cast<unsigned char *>(target_one_info));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user