8328741: serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java failed with unexpected owner

Reviewed-by: lmesnik, cjplummer
This commit is contained in:
Serguei Spitsyn 2024-04-24 09:02:02 +00:00
parent e681e9b4d7
commit 174d62652c
4 changed files with 34 additions and 94 deletions

View File

@ -53,9 +53,9 @@ public class ObjectMonitorUsage {
static Object lockCheck = new Object();
native static int getRes();
native static int waitsToEnter();
native static int waitsToBeNotified();
native static int setTestedMonitor(Object monitor);
native static void ensureBlockedOnEnter(Thread thread);
native static void ensureWaitingToBeNotified(Thread thread);
native static void check(Object obj, Thread owner,
int entryCount, int waiterCount, int notifyWaiterCount);
@ -87,10 +87,9 @@ public class ObjectMonitorUsage {
Thread[] threads = new Thread[NUMBER_OF_WAITING_THREADS];
for (int i = 0; i < NUMBER_OF_WAITING_THREADS; i++) {
// the WaitingTask has to wait to be notified in lockCheck.wait()
threads[i] = startTask(i, new WaitingTask(), isVirtual, "Waiting");
}
while (waitsToBeNotified() < NUMBER_OF_WAITING_THREADS) {
sleep(1);
Thread thread = startTask(i, new WaitingTask(), isVirtual, "Waiting");
ensureWaitingToBeNotified(thread);
threads[i] = thread;
}
return threads;
}
@ -99,10 +98,9 @@ public class ObjectMonitorUsage {
Thread[] threads = new Thread[NUMBER_OF_ENTERING_THREADS];
for (int i = 0; i < NUMBER_OF_ENTERING_THREADS; i++) {
// the EnteringTask has to be blocked at the lockCheck enter
threads[i] = startTask(i, new EnteringTask(), isVirtual, "Entering");
}
while (waitsToEnter() < NUMBER_OF_ENTERING_THREADS) {
sleep(1);
Thread thread = startTask(i, new EnteringTask(), isVirtual, "Entering");
ensureBlockedOnEnter(thread);
threads[i] = thread;
}
return threads;
}

View File

@ -32,11 +32,8 @@ extern "C" {
#define STATUS_FAILED 2
static jvmtiEnv *jvmti = nullptr;
static jrawMonitorID event_lock = nullptr;
static jint result = PASSED;
static int check_idx = 0;
static int waits_to_enter = 0;
static int waits_to_be_notified = 0;
static jobject tested_monitor = nullptr;
static bool is_tested_monitor(JNIEnv *jni, jobject monitor) {
@ -53,47 +50,10 @@ static void log_event(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread,
deallocate(jvmti, jni, (void*)tname);
}
JNIEXPORT void JNICALL
MonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jobject monitor) {
RawMonitorLocker rml(jvmti, jni, event_lock);
if (is_tested_monitor(jni, monitor)) {
waits_to_enter++;
log_event(jvmti, jni, thread, "MonitorContendedEnter", waits_to_enter);
}
}
JNIEXPORT void JNICALL
MonitorContendedEntered(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jobject monitor) {
RawMonitorLocker rml(jvmti, jni, event_lock);
if (is_tested_monitor(jni, monitor)) {
waits_to_enter--;
log_event(jvmti, jni, thread, "MonitorContendedEntered", waits_to_enter);
}
}
JNIEXPORT void JNICALL
MonitorWait(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jobject monitor, jlong timeout) {
RawMonitorLocker rml(jvmti, jni, event_lock);
if (is_tested_monitor(jni, monitor)) {
waits_to_be_notified++;
log_event(jvmti, jni, thread, "MonitorWait", waits_to_be_notified);
}
}
JNIEXPORT void JNICALL
MonitorWaited(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jobject monitor, jboolean timed_out) {
RawMonitorLocker rml(jvmti, jni, event_lock);
if (is_tested_monitor(jni, monitor)) {
waits_to_be_notified--;
log_event(jvmti, jni, thread, "MonitorWaited", waits_to_be_notified);
}
}
jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
jint res;
jvmtiError err;
jvmtiCapabilities caps;
jvmtiEventCallbacks callbacks;
res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
if (res != JNI_OK || jvmti == nullptr) {
@ -116,17 +76,6 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
LOG("Warning: Monitor events are not implemented\n");
return JNI_ERR;
}
memset(&callbacks, 0, sizeof(callbacks));
callbacks.MonitorContendedEnter = &MonitorContendedEnter;
callbacks.MonitorContendedEntered = &MonitorContendedEntered;
callbacks.MonitorWait = &MonitorWait;
callbacks.MonitorWaited = &MonitorWaited;
err = jvmti->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks));
check_jvmti_error(err, "Agent_Initialize: error in JVMTI SetEventCallbacks");
event_lock = create_raw_monitor(jvmti, "Events Monitor");
return JNI_OK;
}
@ -216,41 +165,20 @@ Java_ObjectMonitorUsage_check(JNIEnv *jni, jclass cls, jobject obj, jthread owne
JNIEXPORT void JNICALL
Java_ObjectMonitorUsage_setTestedMonitor(JNIEnv *jni, jclass cls, jobject monitor) {
jvmtiError err;
jvmtiEventMode event_mode = (monitor != nullptr) ? JVMTI_ENABLE : JVMTI_DISABLE;
RawMonitorLocker rml(jvmti, jni, event_lock);
if (tested_monitor != nullptr) {
jni->DeleteGlobalRef(tested_monitor);
}
tested_monitor = (monitor != nullptr) ? jni->NewGlobalRef(monitor) : nullptr;
waits_to_enter = 0;
waits_to_be_notified = 0;
err = jvmti->SetEventNotificationMode(event_mode, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, nullptr);
check_jvmti_status(jni, err, "setTestedMonitor: error in JVMTI SetEventNotificationMode #1");
err = jvmti->SetEventNotificationMode(event_mode, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, nullptr);
check_jvmti_status(jni, err, "setTestedMonitor: error in JVMTI SetEventNotificationMode #2");
err = jvmti->SetEventNotificationMode(event_mode, JVMTI_EVENT_MONITOR_WAIT, nullptr);
check_jvmti_status(jni, err, "setTestedMonitor: error in JVMTI SetEventNotificationMode #3");
err = jvmti->SetEventNotificationMode(event_mode, JVMTI_EVENT_MONITOR_WAITED, nullptr);
check_jvmti_status(jni, err, "setTestedMonitor: error in JVMTI SetEventNotificationMode #4");
}
JNIEXPORT jint JNICALL
Java_ObjectMonitorUsage_waitsToEnter(JNIEnv *jni, jclass cls) {
RawMonitorLocker rml(jvmti, jni, event_lock);
return waits_to_enter;
JNIEXPORT void JNICALL
Java_ObjectMonitorUsage_ensureBlockedOnEnter(JNIEnv *jni, jclass cls, jthread thread) {
wait_for_state(jvmti, jni, thread, JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER);
}
JNIEXPORT jint JNICALL
Java_ObjectMonitorUsage_waitsToBeNotified(JNIEnv *jni, jclass cls) {
RawMonitorLocker rml(jvmti, jni, event_lock);
return waits_to_be_notified;
JNIEXPORT void JNICALL
Java_ObjectMonitorUsage_ensureWaitingToBeNotified(JNIEnv *jni, jclass cls, jthread thread) {
wait_for_state(jvmti, jni, thread, JVMTI_THREAD_STATE_WAITING_INDEFINITELY);
}
JNIEXPORT jint JNICALL

View File

@ -216,11 +216,7 @@ test_vthread_resume_all(JNIEnv* jni, const jthread* thread_list, int suspend_mas
check_jvmti_status(jni, err, "test_vthread_resume_all: error in JVMTI ResumeAllVirtualThreads");
// wait a second to give the breakpoints a chance to be hit.
#ifdef WINDOWS
Sleep(1000);
#else
sleep(1);
#endif
sleep_sec(1);
for (int idx = 0; idx < EXCLUDE_CNT; idx++) {
// Disable Breakpoint events on excluded thread

View File

@ -56,7 +56,7 @@
#define COMPLAIN LOG
void sleep_ms(int millis);
const char* TranslateState(jint flags);
const char* TranslateError(jvmtiError err);
@ -380,6 +380,24 @@ find_method(jvmtiEnv *jvmti, JNIEnv *jni, jclass klass, const char* mname) {
return method;
}
// Wait for target thread to reach the required JVMTI thread state.
// The state jint bitmask is returned by the JVMTI GetThreadState.
// Some examples are:
// - JVMTI_THREAD_STATE_WAITING
// - JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER
// - JVMTI_THREAD_STATE_SLEEPING
static void
wait_for_state(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jint exp_state) {
while (true) {
// Allow a bitmask to designate expected thread state. E.g., if two bits are expected
// than check they both are present in the state mask returned by JVMTI GetThreadState.
if ((get_thread_state(jvmti, jni, thread) & exp_state) == exp_state) {
break;
}
sleep_ms(100);
}
}
#define MAX_FRAME_COUNT_PRINT_STACK_TRACE 200
static void