diff --git a/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java b/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java index b0f7987053bb9..eb34b5cebdf9c 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java +++ b/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java @@ -52,6 +52,8 @@ public class ObjectMonitorUsage { static Object lockCheck = new Object(); native static int getRes(); + native static int waitsToEnter(); + native static int setTestedMonitor(Object monitor); native static void check(Object obj, Thread owner, int entryCount, int waiterCount, int notifyWaiterCount); @@ -63,6 +65,14 @@ static String vtag(boolean isVirtual) { return isVirtual ? "virtual" : "platform"; } + static void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + // ignore + } + } + static Thread startTask(int idx, TestTask task, boolean isVirtual, String kind) { Thread thread = isVirtual ? Thread.ofVirtual().name(kind + "VT" + idx).start(task) : Thread.ofPlatform().name(kind + "PT" + idx).start(task); @@ -85,6 +95,9 @@ static Thread[] startEnteringThreads(boolean isVirtual) { // 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); + } return threads; } @@ -135,6 +148,7 @@ static void test1(boolean isVirtual) { String vtag = vtag(isVirtual); log("\n###test1: started " + vtag); + setTestedMonitor(lockCheck); Thread[] eThreads = null; synchronized (lockCheck) { @@ -155,6 +169,7 @@ static void test1(boolean isVirtual) { 0 /* count of threads waiting to be notified: 0 */); } + setTestedMonitor(null); joinThreads(eThreads); log("###test1: finished " + vtag); } @@ -169,6 +184,7 @@ static void test2(boolean isVirtual) throws Error { String vtag = vtag(isVirtual); log("\n###test2: started " + vtag); + setTestedMonitor(lockCheck); Thread[] wThreads = startWaitingThreads(isVirtual); Thread[] eThreads = null; @@ -185,6 +201,7 @@ static void test2(boolean isVirtual) throws Error { lockCheck.notifyAll(); } + setTestedMonitor(null); joinThreads(wThreads); joinThreads(eThreads); log("###test2: finished " + vtag); @@ -206,6 +223,7 @@ static void test3(boolean isVirtual) throws Error { String vtag = vtag(isVirtual); log("\n###test3: started " + vtag); + setTestedMonitor(lockCheck); Thread[] wThreads = startWaitingThreads(isVirtual); Thread[] eThreads = null; @@ -241,6 +259,7 @@ static void test3(boolean isVirtual) throws Error { NUMBER_OF_WAITING_THREADS - i - 1); } } + setTestedMonitor(null); joinThreads(wThreads); joinThreads(eThreads); log("###test3: finished " + vtag); diff --git a/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/libObjectMonitorUsage.cpp b/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/libObjectMonitorUsage.cpp index 4187e290a1798..a49a37c3baf6d 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/libObjectMonitorUsage.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/libObjectMonitorUsage.cpp @@ -32,44 +32,71 @@ extern "C" { #define STATUS_FAILED 2 static jvmtiEnv *jvmti = nullptr; -static jvmtiCapabilities caps; +static jrawMonitorID event_lock = nullptr; static jint result = PASSED; static int check_idx = 0; +static int waits_to_enter = 0; +static jobject tested_monitor = nullptr; + +static bool is_tested_monitor(JNIEnv *jni, jobject monitor) { + if (tested_monitor == nullptr) { + return false; // tested_monitor was not set yet + } + return jni->IsSameObject(monitor, tested_monitor) == JNI_TRUE; +} + +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++; + } +} + +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--; + } +} + 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) { LOG("Wrong result of a valid call to GetEnv !\n"); return JNI_ERR; } - err = jvmti->GetPotentialCapabilities(&caps); - if (err != JVMTI_ERROR_NONE) { - LOG("(GetPotentialCapabilities) unexpected error: %s (%d)\n", - TranslateError(err), err); - return JNI_ERR; - } + check_jvmti_error(err, "Agent_Initialize: error in JVMTI GetPotentialCapabilities"); err = jvmti->AddCapabilities(&caps); - if (err != JVMTI_ERROR_NONE) { - LOG("(AddCapabilities) unexpected error: %s (%d)\n", - TranslateError(err), err); - return JNI_ERR; - } + check_jvmti_error(err, "Agent_Initialize: error in JVMTI AddCapabilities"); err = jvmti->GetCapabilities(&caps); - if (err != JVMTI_ERROR_NONE) { - LOG("(GetCapabilities) unexpected error: %s (%d)\n", - TranslateError(err), err); - return JNI_ERR; - } + check_jvmti_error(err, "Agent_Initialize: error in JVMTI GetCapabilities"); if (!caps.can_get_monitor_info) { LOG("Warning: GetObjectMonitorUsage is not implemented\n"); } + if (!caps.can_generate_monitor_events) { + LOG("Warning: Monitor events are not implemented\n"); + return JNI_ERR; + } + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.MonitorContendedEnter = &MonitorContendedEnter; + callbacks.MonitorContendedEntered = &MonitorContendedEntered; + + 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; } @@ -84,13 +111,7 @@ Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { return Agent_Initialize(jvm, options, reserved); } -static void dealloc(JNIEnv *jni, char* mem) { - jvmtiError err = jvmti->Deallocate((unsigned char*)mem); - check_jvmti_status(jni, err, "error in JVMTI Deallocate"); -} - -static void -print_monitor_info(JNIEnv *jni, jvmtiMonitorUsage &inf) { +static void print_monitor_info(JNIEnv *jni, jvmtiMonitorUsage &inf) { jvmtiError err; jvmtiThreadInfo tinf; @@ -102,7 +123,7 @@ print_monitor_info(JNIEnv *jni, jvmtiMonitorUsage &inf) { check_jvmti_status(jni, err, "error in JVMTI GetThreadInfo"); LOG(">>> owner: %s (0x%p)\n", tinf.name, inf.owner); - dealloc(jni, tinf.name); + deallocate(jvmti, jni, tinf.name); } LOG(">>> entry_count: %d\n", inf.entry_count); LOG(">>> waiter_count: %d\n", inf.waiter_count); @@ -115,7 +136,7 @@ print_monitor_info(JNIEnv *jni, jvmtiMonitorUsage &inf) { check_jvmti_status(jni, err, "error in JVMTI GetThreadInfo"); LOG(">>> %2d: %s (0x%p)\n", j, tinf.name, inf.waiters[j]); - dealloc(jni, tinf.name); + deallocate(jvmti, jni, tinf.name); } } if (inf.notify_waiter_count > 0) { @@ -125,7 +146,7 @@ print_monitor_info(JNIEnv *jni, jvmtiMonitorUsage &inf) { check_jvmti_status(jni, err, "error in JVMTI GetThreadInfo"); LOG(">>> %2d: %s (0x%p)\n", j, tinf.name, inf.notify_waiters[j]); - dealloc(jni, tinf.name); + deallocate(jvmti, jni, tinf.name); } } } @@ -164,6 +185,32 @@ 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; + + 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"); +} + +JNIEXPORT jint JNICALL +Java_ObjectMonitorUsage_waitsToEnter(JNIEnv *jni, jclass cls) { + RawMonitorLocker rml(jvmti, jni, event_lock); + return waits_to_enter; +} + JNIEXPORT jint JNICALL Java_ObjectMonitorUsage_getRes(JNIEnv *jni, jclass cls) { return result;