8308000: add PopFrame support for virtual threads
Reviewed-by: lmesnik, alanb
This commit is contained in:
parent
41beb448d2
commit
928fcf9751
@ -2958,6 +2958,10 @@ err = (*jvmti)->Deallocate(jvmti, stack_info);
|
||||
<jthread impl="noconvert"/>
|
||||
<description>
|
||||
The thread whose current frame is to be popped.
|
||||
The <functionlink id="PopFrame"></functionlink> function may be used to
|
||||
pop the current frame of a virtual thread when it is suspended at an event.
|
||||
An implementation may support popping the current frame of a suspended
|
||||
virtual thread in other cases.
|
||||
</description>
|
||||
</param>
|
||||
</parameters>
|
||||
@ -2967,8 +2971,8 @@ err = (*jvmti)->Deallocate(jvmti, stack_info);
|
||||
The implementation is unable to pop this frame.
|
||||
</error>
|
||||
<error id="JVMTI_ERROR_OPAQUE_FRAME">
|
||||
The thread is a virtual thread and the implementation is unable
|
||||
to pop this frame.
|
||||
The thread is a suspended virtual thread and the implementation
|
||||
was unable to pop the current frame.
|
||||
</error>
|
||||
<error id="JVMTI_ERROR_THREAD_NOT_SUSPENDED">
|
||||
Thread was not suspended and was not the current thread.
|
||||
|
@ -1883,13 +1883,26 @@ JvmtiEnv::PopFrame(jthread thread) {
|
||||
oop thread_obj = nullptr;
|
||||
jvmtiError err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj);
|
||||
|
||||
if (thread_obj != nullptr && thread_obj->is_a(vmClasses::BaseVirtualThread_klass())) {
|
||||
// No support for virtual threads (yet).
|
||||
return JVMTI_ERROR_OPAQUE_FRAME;
|
||||
}
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
return err;
|
||||
}
|
||||
bool is_virtual = thread_obj != nullptr && thread_obj->is_a(vmClasses::BaseVirtualThread_klass());
|
||||
|
||||
if (is_virtual) {
|
||||
if (!is_JavaThread_current(java_thread, thread_obj)) {
|
||||
if (!is_vthread_suspended(thread_obj, java_thread)) {
|
||||
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
||||
}
|
||||
if (java_thread == nullptr) { // unmounted virtual thread
|
||||
return JVMTI_ERROR_OPAQUE_FRAME;
|
||||
}
|
||||
}
|
||||
} else { // platform thread
|
||||
if (java_thread != current_thread && !java_thread->is_suspended() &&
|
||||
!java_thread->is_carrier_thread_suspended()) {
|
||||
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
||||
}
|
||||
}
|
||||
|
||||
// retrieve or create the state
|
||||
JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread);
|
||||
|
@ -2211,11 +2211,6 @@ UpdateForPopTopFrameClosure::doit(Thread *target, bool self) {
|
||||
}
|
||||
assert(java_thread == _state->get_thread(), "Must be");
|
||||
|
||||
if (!self && !java_thread->is_suspended() && !java_thread->is_carrier_thread_suspended()) {
|
||||
_result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if a PopFrame was already in progress
|
||||
if (java_thread->popframe_condition() != JavaThread::popframe_inactive) {
|
||||
// Probably possible for JVMTI clients to trigger this, but the
|
||||
|
@ -45,7 +45,6 @@ vmTestbase/nsk/jvmti/GetCurrentThreadCpuTime/curthrcputime001/TestDescription.ja
|
||||
vmTestbase/nsk/jvmti/GetThreadCpuTime/thrcputime001/TestDescription.java 8300708 generic-all
|
||||
vmTestbase/nsk/jvmti/NotifyFramePop/nframepop002/TestDescription.java 8300708 generic-all
|
||||
vmTestbase/nsk/jvmti/NotifyFramePop/nframepop003/TestDescription.java 8300708 generic-all
|
||||
vmTestbase/nsk/jvmti/PopFrame/popframe004/TestDescription.java 8300708 generic-all
|
||||
vmTestbase/nsk/jvmti/StopThread/stopthrd006/TestDescription.java 8300708 generic-all
|
||||
vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t012/TestDescription.java 8300708 generic-all
|
||||
vmTestbase/nsk/jvmti/SetLocalVariable/setlocal004/TestDescription.java 8300708 generic-all
|
||||
@ -119,6 +118,8 @@ vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes002/TestDescription.java 8
|
||||
vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes003/TestDescription.java 8285414 generic-all
|
||||
vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes004/TestDescription.java 8285414 generic-all
|
||||
|
||||
vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes001/TestDescription.java 8308237 generic-all
|
||||
|
||||
####
|
||||
## JVMTI ForceEarlyReturn not supported for vthreads (JVMTI_ERROR_OPAQUE_FRAME)
|
||||
## Note forceEarlyReturn002 was converted to support vthreads. The rest were not
|
||||
|
@ -115,10 +115,6 @@ test_unsupported_jvmti_functions(jvmtiEnv *jvmti, JNIEnv *jni, jthread vthread,
|
||||
fatal(jni, "Virtual threads are not supported");
|
||||
}
|
||||
|
||||
LOG("Testing PopFrame\n");
|
||||
err = jvmti->PopFrame(vthread);
|
||||
check_jvmti_error_opaque_frame(jni, "PopFrame", err);
|
||||
|
||||
LOG("Testing ForceEarlyReturnVoid\n");
|
||||
err = jvmti->ForceEarlyReturnVoid(vthread);
|
||||
check_jvmti_error_opaque_frame(jni, "ForceEarlyReturnVoid", err);
|
||||
|
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
* 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 id=default
|
||||
* @summary Verifies JVMTI PopFrame support for virtual threads.
|
||||
* @requires vm.continuations
|
||||
* @run main/othervm/native -agentlib:PopFrameTest PopFrameTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=no-vmcontinuations
|
||||
* @summary Verifies JVMTI PopFrame support for bound virtual threads.
|
||||
* @run main/othervm/native -agentlib:PopFrameTest -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations PopFrameTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=platform
|
||||
* @summary Verifies JVMTI PopFrame support for platform threads.
|
||||
* @run main/othervm/native -agentlib:PopFrameTest PopFrameTest platform
|
||||
*/
|
||||
|
||||
import java.lang.AssertionError;
|
||||
|
||||
/*
|
||||
* The test exercises the JVMTI function PopFrame.
|
||||
* The test creates a new virtual or platform thread.
|
||||
* Its method run() invokes the following methods:
|
||||
* - method A() that is blocked on a monitor
|
||||
* - method B() that is stopped at a breakpoint
|
||||
* - method C() that forces agent to call PopFrame on its own thread
|
||||
* JVMTI PopFrame is called in all cases.
|
||||
*/
|
||||
public class PopFrameTest {
|
||||
private static final String agentLib = "PopFrameTest";
|
||||
static final int JVMTI_ERROR_NONE = 0;
|
||||
static final int THREAD_NOT_SUSPENDED = 13;
|
||||
static final int OPAQUE_FRAME = 32;
|
||||
static final int PASSED = 0;
|
||||
static final int FAILED = 2;
|
||||
|
||||
static void log(String str) { System.out.println(str); }
|
||||
|
||||
static native void prepareAgent(Class taskClass, boolean doPopFrame);
|
||||
static native void suspendThread(Thread thread);
|
||||
static native void resumeThread(Thread thread);
|
||||
static native void ensureAtBreakpoint();
|
||||
static native void notifyAtBreakpoint();
|
||||
static native int popFrame(Thread thread);
|
||||
|
||||
static int status = PASSED;
|
||||
static boolean is_virtual = true;
|
||||
|
||||
static void setFailed(String msg) {
|
||||
log("\nFAILED: " + msg);
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
static void throwFailed(String msg) {
|
||||
log("\nFAILED: " + msg);
|
||||
throw new RuntimeException("PopFrameTest failed!");
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
is_virtual = !(args.length > 0 && args[0].equals("platform"));
|
||||
run();
|
||||
if (status == FAILED) {
|
||||
throwFailed("PopFrameTest!");
|
||||
}
|
||||
log("\nPopFrameTest passed");
|
||||
}
|
||||
|
||||
public static void run() {
|
||||
TestTask testTask = new TestTask();
|
||||
Thread testTaskThread = null;
|
||||
int errCode;
|
||||
|
||||
log("\nMain #A: method A() must be blocked on entering a synchronized statement");
|
||||
if (is_virtual) {
|
||||
testTaskThread = Thread.ofVirtual().name("TestTaskThread").start(testTask);
|
||||
} else {
|
||||
testTaskThread = Thread.ofPlatform().name("TestTaskThread").start(testTask);
|
||||
}
|
||||
|
||||
{
|
||||
TestTask.ensureAtPointA();
|
||||
|
||||
log("\nMain #A.1: unsuspended");
|
||||
errCode = popFrame(testTaskThread);
|
||||
if (errCode != THREAD_NOT_SUSPENDED) {
|
||||
throwFailed("Main #A.1: expected THREAD_NOT_SUSPENDED instead of: " + errCode);
|
||||
} else {
|
||||
log("Main #A.1: got expected THREAD_NOT_SUSPENDED");
|
||||
}
|
||||
|
||||
log("\nMain #A.2: suspended");
|
||||
suspendThread(testTaskThread);
|
||||
errCode = popFrame(testTaskThread);
|
||||
if (errCode != JVMTI_ERROR_NONE) {
|
||||
throwFailed("Main #A.2: expected JVMTI_ERROR_NONE instead of: " + errCode);
|
||||
} else {
|
||||
log("Main #A.2: got expected JVMTI_ERROR_NONE");
|
||||
}
|
||||
resumeThread(testTaskThread);
|
||||
TestTask.clearDoLoop();
|
||||
TestTask.sleep(5);
|
||||
}
|
||||
|
||||
log("\nMain #B: method B() must be blocked in a breakpoint event handler");
|
||||
{
|
||||
ensureAtBreakpoint();
|
||||
|
||||
log("\nMain #B.1: unsuspended");
|
||||
errCode = popFrame(testTaskThread);
|
||||
if (errCode != THREAD_NOT_SUSPENDED) {
|
||||
throwFailed("Main #B.1: expected THREAD_NOT_SUSPENDED instead of: " + errCode);
|
||||
}
|
||||
log("Main #B.1: got expected THREAD_NOT_SUSPENDED");
|
||||
|
||||
log("\nMain #B.2: suspended");
|
||||
suspendThread(testTaskThread);
|
||||
errCode = popFrame(testTaskThread);
|
||||
if (errCode != JVMTI_ERROR_NONE) {
|
||||
throwFailed("Main #B.2: expected JVMTI_ERROR_NONE");
|
||||
}
|
||||
log("Main #B.2: got expected JVMTI_ERROR_NONE");
|
||||
resumeThread(testTaskThread);
|
||||
notifyAtBreakpoint();
|
||||
|
||||
log("\nMain #B.3: unsuspended, call PopFrame on own thread");
|
||||
ensureAtBreakpoint();
|
||||
notifyAtBreakpoint();
|
||||
TestTask.sleep(5);
|
||||
}
|
||||
|
||||
log("\nMain #C: method C() calls PopFrame on its own thread");
|
||||
{
|
||||
// PopFrame is called from method C() on own thread. Expected to return OPAQUE_FRAME.
|
||||
// No suspension of the test task thread is required or can be done in this case.
|
||||
TestTask.ensureFinished();
|
||||
}
|
||||
|
||||
try {
|
||||
testTaskThread.join();
|
||||
} catch (InterruptedException ex) {
|
||||
throwFailed("Unexpected " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class TestTask implements Runnable {
|
||||
static void log(String str) { System.out.println(str); }
|
||||
|
||||
static volatile boolean doLoop = true;
|
||||
static volatile boolean atPointA = false;
|
||||
static volatile boolean finished = false;
|
||||
|
||||
static void sleep(long millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("Interruption in TestTask.sleep: \n\t" + e);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure thread is ready.
|
||||
static void ensureAtPointA() {
|
||||
while (!atPointA) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure thread is finished.
|
||||
static void ensureFinished() {
|
||||
while (!finished) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void clearDoLoop() {
|
||||
doLoop = false;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
log("TestTask.run: started");
|
||||
|
||||
A();
|
||||
sleep(1); // to cause yield
|
||||
|
||||
prepareAgent(TestTask.class, false); // No doPopFrame
|
||||
B();
|
||||
sleep(1); // to cause yield
|
||||
|
||||
prepareAgent(TestTask.class, true); // doPopFrame
|
||||
B();
|
||||
sleep(1); // to cause yield
|
||||
|
||||
C();
|
||||
finished = true;
|
||||
}
|
||||
|
||||
// Method is busy in a while loop.
|
||||
// PopFrame is used two times:
|
||||
// - when not suspended: THREAD_NOT_SUSPENDED is expected
|
||||
// - when suspended: JVMTI_ERROR_NONE is expected
|
||||
static void A() {
|
||||
log("TestTask.A: started");
|
||||
atPointA = true;
|
||||
while (doLoop) {
|
||||
}
|
||||
log("TestTask.A: finished");
|
||||
}
|
||||
|
||||
// A breakpoint is set at start of this method.
|
||||
// PopFrame is used two times:
|
||||
// - when not suspended: THREAD_NOT_SUSPENDED is expected
|
||||
// - when suspended: expected to succeed
|
||||
static void B() {
|
||||
log("TestTask.B: started");
|
||||
}
|
||||
|
||||
// This method uses PopFrame on its own thread. It is expected to return OPAQUE_FRAME.
|
||||
static void C() {
|
||||
log("TestTask.C: started");
|
||||
int errCode = PopFrameTest.popFrame(Thread.currentThread());
|
||||
if (errCode == OPAQUE_FRAME) {
|
||||
log("TestTask.C: got expected OPAQUE_FRAME");
|
||||
} else {
|
||||
setFailed("TestTask.C: expected OPAQUE_FRAME from PopFrame instead of: " + errCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include "jvmti.h"
|
||||
#include "jvmti_common.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
static jvmtiEnv *jvmti;
|
||||
static jmethodID mid_B;
|
||||
static jrawMonitorID monitor;
|
||||
static jboolean do_pop_frame;
|
||||
static volatile bool bp_sync_reached;
|
||||
|
||||
static void JNICALL
|
||||
Breakpoint(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread,
|
||||
jmethodID method, jlocation location) {
|
||||
jvmtiError err;
|
||||
|
||||
if (method != mid_B) {
|
||||
fatal(jni, "Breakpoint: Failed with wrong location: expected in method TestTask.B()");
|
||||
}
|
||||
err = jvmti->ClearBreakpoint(mid_B, 0);
|
||||
check_jvmti_status(jni, err, "Breakpoint: Failed in JVMTI ClearBreakpoint");
|
||||
|
||||
LOG("Breakpoint: In method TestTask.B(): before sync section\n");
|
||||
{
|
||||
RawMonitorLocker rml(jvmti, jni, monitor);
|
||||
bp_sync_reached = true;
|
||||
rml.wait(0);
|
||||
}
|
||||
LOG("Breakpoint: In method TestTask.B(): after sync section\n");
|
||||
|
||||
if (do_pop_frame != 0) {
|
||||
err = jvmti->PopFrame(thread);
|
||||
LOG("Breakpoint: PopFrame returned code: %s (%d)\n", TranslateError(err), err);
|
||||
check_jvmti_status(jni, err, "Breakpoint: Failed in PopFrame");
|
||||
}
|
||||
LOG("Breakpoint: In method TestTask.B() finished\n");
|
||||
}
|
||||
|
||||
jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
|
||||
static jvmtiCapabilities caps;
|
||||
static jvmtiEventCallbacks callbacks;
|
||||
jvmtiError err;
|
||||
jint res;
|
||||
|
||||
LOG("Agent init\n");
|
||||
res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
|
||||
if (res != JNI_OK || jvmti == NULL) {
|
||||
LOG("Agent init: Failed in GetEnv!\n");
|
||||
return JNI_ERR;
|
||||
}
|
||||
err = jvmti->GetPotentialCapabilities(&caps);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
LOG("Agent init: Failed in GetPotentialCapabilities: %s (%d)\n", TranslateError(err), err);
|
||||
return JNI_ERR;
|
||||
}
|
||||
err = jvmti->AddCapabilities(&caps);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
LOG("Agent init: Failed in AddCapabilities: %s (%d)\n", TranslateError(err), err);
|
||||
return JNI_ERR;
|
||||
}
|
||||
err = jvmti->GetCapabilities(&caps);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
LOG("Agent init: Failed in GetCapabilities: %s (%d)\n", TranslateError(err), err);
|
||||
return JNI_ERR;
|
||||
}
|
||||
if (!caps.can_generate_breakpoint_events) {
|
||||
LOG("Agent init: Failed: Breakpoint event is not implemented\n");
|
||||
return JNI_ERR;
|
||||
}
|
||||
callbacks.Breakpoint = &Breakpoint;
|
||||
err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
LOG("Agent init: Failed in SetEventCallbacks: %s (%d)\n", TranslateError(err), err);
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
monitor = create_raw_monitor(jvmti, "Raw monitor to test");
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
extern JNIEXPORT jint JNICALL
|
||||
Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
|
||||
return Agent_Initialize(jvm, options, reserved);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_PopFrameTest_prepareAgent(JNIEnv *jni, jclass cls, jclass task_clazz, jboolean do_pop) {
|
||||
jvmtiError err;
|
||||
|
||||
LOG("Main: prepareAgent started\n");
|
||||
|
||||
if (jvmti == NULL) {
|
||||
fatal(jni, "prepareAgent: Failed as JVMTI client was not properly loaded!\n");
|
||||
}
|
||||
do_pop_frame = do_pop;
|
||||
|
||||
mid_B = jni->GetStaticMethodID(task_clazz, "B", "()V");
|
||||
if (mid_B == NULL) {
|
||||
fatal(jni, "prepareAgent: Failed to find Method ID for method: TestTask.B()\n");
|
||||
}
|
||||
err = jvmti->SetBreakpoint(mid_B, 0);
|
||||
check_jvmti_status(jni, err, "prepareAgent: Failed in JVMTI SetBreakpoint");
|
||||
|
||||
set_event_notification_mode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL);
|
||||
|
||||
LOG("Main: prepareAgent finished\n");
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_PopFrameTest_suspendThread(JNIEnv *jni, jclass cls, jthread thread) {
|
||||
LOG("Main: suspendThread\n");
|
||||
suspend_thread(jvmti, jni, thread);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_PopFrameTest_resumeThread(JNIEnv *jni, jclass cls, jthread thread) {
|
||||
LOG("Main: resumeThread\n");
|
||||
resume_thread(jvmti, jni, thread);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_PopFrameTest_popFrame(JNIEnv *jni, jclass cls, jthread thread) {
|
||||
jvmtiError err = jvmti->PopFrame(thread);
|
||||
LOG("Main: popFrame: PopFrame returned code: %s (%d)\n", TranslateError(err), err);
|
||||
return (jint)err;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_PopFrameTest_ensureAtBreakpoint(JNIEnv *jni, jclass cls) {
|
||||
bool need_stop = false;
|
||||
|
||||
LOG("Main: ensureAtBreakpoint\n");
|
||||
while (!need_stop) {
|
||||
RawMonitorLocker rml(jvmti, jni, monitor);
|
||||
need_stop = bp_sync_reached;
|
||||
sleep_ms(1); // 1 millisecond
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_PopFrameTest_notifyAtBreakpoint(JNIEnv *jni, jclass cls) {
|
||||
LOG("Main: notifyAtBreakpoint\n");
|
||||
RawMonitorLocker rml(jvmti, jni, monitor);
|
||||
bp_sync_reached = false;
|
||||
rml.notify_all();
|
||||
}
|
||||
|
||||
} // extern "C"
|
@ -87,10 +87,6 @@ test_unsupported_jvmti_functions(jvmtiEnv *jvmti, JNIEnv *jni, jthread vthread)
|
||||
|
||||
LOG("Testing JVMTI functions which should not accept a virtual thread argument\n");
|
||||
|
||||
LOG("Testing PopFrame\n");
|
||||
err = jvmti->PopFrame(vthread);
|
||||
check_jvmti_error_opaque_frame(jni, "PopFrame", err);
|
||||
|
||||
LOG("Testing ForceEarlyReturnVoid\n");
|
||||
err = jvmti->ForceEarlyReturnVoid(vthread);
|
||||
check_jvmti_error_opaque_frame(jni, "ForceEarlyReturnVoid", err);
|
||||
|
Loading…
Reference in New Issue
Block a user